home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / tjgold.zip / INSTALL.001 / GOLDMEMO.PAS < prev    next >
Pascal/Delphi Source File  |  1995-07-12  |  102KB  |  3,243 lines

  1. {--------------------------------------------------------------------------}
  2. {                Product: TechnoJock's Turbo Toolkit                       }
  3. {                Version: GOLD                                             }
  4. {                Build:   1.01                                             }
  5. {                                                                          }
  6. {                Copyright 1986-1995  TechnoJock Software, Inc.            }
  7. {                           All Rights Reserved                            }
  8. {                          Restricted by License                           }
  9. {--------------------------------------------------------------------------}
  10.  
  11.                     {**********************************}
  12.                     {**       Unit:   GOLDMEMO       **}
  13.                     {**********************************}
  14.  
  15. {++++++++++++++++++++++++++++++} unit GOLDMEMO; {++++++++++++++++++++++++++++}
  16.  
  17. {$I GOLDFLAG.INC}
  18. {$IFNDEF GOLDMEMO}
  19.    {$DEFINE GOLDMEMO}
  20. {$ENDIF}
  21.  
  22. {++++++++++++++++++++++++++++++++} INTERFACE {+++++++++++++++++++++++++++++++}
  23.  
  24. uses DOS, CRT, GoldHard, GoldMisc, GoldTint, GoldIO, GoldStr,
  25.      GoldKey, GoldFast, GoldWin, GoldLink, GoldList;
  26.  
  27. const
  28.    FirstMemoCol = MemoHi;
  29.    LastMemoCol  = MemoIcons;
  30.  
  31. type
  32.    MemoCfgPtr = ^MemoCfg;
  33.  
  34.    MemoGetLineFunc = function(MP:MemoCfgPtr;LineNum: longint): string;
  35.    MemoSetLineFunc = procedure(MP:MemoCfgPtr;LineNum: longint;Str:string);
  36.    MemoDelLineFunc = procedure(MP:MemoCfgPtr;LineNum: longint);
  37.    MemoInsLineFunc = function(MP:MemoCfgPtr;LineNum: longint):longint;
  38.    MemoInsModeFunc = procedure(Insert:boolean);
  39.  
  40.    MemoCharHook    = procedure(MP:MemoCfgPtr;var Code:word; var X,Y:byte);
  41.    MemoHindHook    = procedure(MP:MemoCfgPtr);
  42.    MemoCloseProc   = function(MemoDetails:MemoCfgPtr; Handle:integer):boolean;
  43.  
  44.    MemoTints = array[FirstMemoCol..LastMemoCol] of byte;
  45.  
  46.    ClipboardPtr = ^ClipBoardBuffer;
  47.    ClipboardBuffer = record
  48.        TotalParagraphs: integer;
  49.        LineList: SingleLL;
  50.        FullLastLine: boolean;
  51.    end; {ClipboardBuffer}
  52.  
  53.    MemoCfg = record
  54.       DataSource: pointer;
  55.       DataType: ListDataSource;
  56.       LeftGap,RightGap,BotGap,TopGap: byte;
  57.       LineStr: string;         {copy of line being edited}
  58.       WX1,WY1,WX2,WY2,WStyle: byte;
  59.       WiType: WinType;
  60.       TotalNodes: longint;
  61.       TopNode: longint;
  62.       CursorPosX: byte;
  63.       TargetPosX: byte;        {target X position when down or up pressed}
  64.       CursorPosY: byte;
  65.       BlockX1: byte;
  66.       BlockY1: longint;
  67.       BlockX2: byte;
  68.       BlockY2: longint;
  69.       FirstCharPos: byte;
  70.       MaxWidth: byte;
  71.       MaxLines: byte;
  72.       AllowEdits: boolean;
  73.       WordWrap: boolean;
  74.       InWindow: boolean;
  75.       DrawVScroll: boolean;
  76.       InsertOn: boolean;
  77.       UsingArray: boolean;
  78.       WarningGiven: boolean;
  79.       IsDirty: boolean;
  80.       Col: MemoTints;
  81.       GetLine: MemoGetLineFunc;
  82.       SetLine: MemoSetLineFunc;
  83.       DelLine: MemoDelLineFunc;
  84.       InsLine: MemoInsLineFunc;
  85.       InsMode: MemoInsModeFunc;
  86.       CharHook: MemoCharHook;
  87.       HindHook: MemoHindHook;
  88.       StrLength: byte;  {length of string element when editing an array}
  89.       {header/footer related}
  90.       Headers: array[1..ListMaxHeaders] of ^string;
  91.       ScrollHeader: boolean;
  92.       Footers: array[1..ListMaxFooters] of ^string;
  93.       ScrollFooter: boolean;
  94.       {internal}
  95.       X1,Y1,X2,Y2,YH: byte;  {dimensions of list (including headings)}
  96.       {desk - internal}
  97.       DeskMemoCloseCallBack: MemoCloseProc;
  98.    end; {MemoCfg}
  99.  
  100.    MemoSet = record
  101.       LastECode: integer;
  102.       WordRightKey: word;
  103.       WordLeftKey: word;
  104.       TopOfWindowKey: word;
  105.       BotOfWindowKey: word;
  106.       TopofMemoKey: word;
  107.       BotofMemoKey: word;
  108.       DeltoScrapKey: word;
  109.       DelBlockKey: word;
  110.       CopyToScrapkey: word;
  111.       InsfromScrapKey: word;
  112.       MarkBlockStartKey: word;
  113.       MarkBlockEndKey: word;
  114.       HideBlockKey: word;
  115.       EndofParaCode: char;
  116.       EndEditKey: word;
  117.       EscEditKey: word;
  118.       WinStyle:byte;
  119.       WType: WinType;
  120.       WX1: byte;          {dimensions of window}
  121.       WY1: byte;
  122.       WX2: byte;
  123.       WY2: byte;
  124.       DefaultLineLength: byte;
  125.       ECode: integer;
  126.       Clipboard: ClipboardPtr;
  127.       {Messages}
  128.       ClipboardMsgTitle:string[40];
  129.       WarningTitle: string[20];
  130.       ClipboardNoMemoryMsg: string[70];
  131.       ClipboardLowMemoryMsg: string[70];
  132.       ClipboardLineFullMsg: string[70];
  133.       MaxLinesMsg: string[50];
  134.       MemoNearlyFullMsg: string[100];
  135.       WordwrapoffMsg: string[80];
  136.       LineFullMsg: string[100];
  137.    end; {MemoSet}
  138.  
  139. procedure MemoSetError(ECode:integer);
  140. function  LastMemoError: integer;
  141. {heading management}
  142. procedure MemoAssignHeader(var MemoDetails: MemoCfg; Line:byte; var Heading:string);
  143. procedure MemoAssignFooter(var MemoDetails: MemoCfg; Line:byte; var Footnote:string);
  144. procedure MemoRemoveHeader(var MemoDetails: MemoCfg; Line:byte);
  145. procedure MemoRemoveFooter(var MemoDetails: MemoCfg; Line:byte);
  146. procedure MemoScrollHeader(var MemoDetails: MemoCfg; On:boolean);
  147. procedure MemoScrollFooter(var MemoDetails: MemoCfg; On:boolean);
  148. {misc settings}
  149. procedure MemoAssignHindHook(var MemoDetails: MemoCfg; Proc:MemoHindHook);
  150. procedure MemoAssignCharHook(var MemoDetails: MemoCfg; Proc:MemoCharHook);
  151. procedure MemoRemoveHindHook(var MemoDetails: MemoCfg);
  152. procedure MemoRemoveCharHook(var MemoDetails: MemoCfg);
  153. procedure MemoSetWordWrap(var MemoDetails: MemoCfg; On:boolean);
  154. procedure MemoSetDirty(var MemoDetails: MemoCfg; On:boolean);
  155. function  MemoIsDirty(var MemoDetails: MemoCfg):boolean;
  156. procedure MemoSetWin(var MemoDetails: MemoCfg; X1,Y1,X2,Y2:integer; Style:byte);
  157. procedure MemoSetGaps(var MemoDetails: MemoCfg; LeftGap,RightGap,BotGap,TopGap: byte);
  158. procedure MemoSetColor(var MemoDetails: MemoCfg; A:TintElement;C:byte);
  159. procedure MemoStoreActiveLine(var MemoDetails: MemoCfg);
  160. {$IFDEF WORDWRAP}
  161. procedure WrapFullNoSpaces(var MemoDetails: MemoCfg);
  162. procedure WrapFull(var MemoDetails: MemoCfg);
  163. procedure CursorUp(var MemoDetails: MemoCfg);
  164. {$ENDIF}
  165. procedure InitMemoCfg(var MemoDetails: MemoCfg);
  166. procedure MemoAssignSLL(var MemoDetails: MemoCfg; var MemoSource: SingleLL);
  167. procedure MemoReAssignSLL(var MemoDetails: MemoCfg; var MemoSource: SingleLL);
  168. procedure MemoAssignDLL(var MemoDetails: MemoCfg; var MemoSource: DoubleLL);
  169. procedure MemoAssignArray(var MemoDetails: MemoCfg; var MemoSource; StrLen:Byte;ArrayElements:byte);
  170. procedure RunMemo(var MemoDetails: MemoCfg; Tit:StrScreen);
  171. function  LaunchMemo(var MemoDetails: MemoCfg;Tit:StrScreen; CloseProc:MemoCloseProc): byte;
  172. {internals}
  173. procedure TurnBlockOff(var MemoDetails:MemoCfg);
  174. procedure MemoProcessKey(var MemoDetails: MemoCfg;var K:word;X,Y:byte);
  175. procedure DisplayMemo(var MemoDetails:MemoCfg; Status:gStatus);
  176. procedure MoveCursor(var MemoDetails: MemoCfg);
  177. procedure MemoSetDirtyFlag(var MemoDetails: MemoCfg);
  178. {$IFDEF CUTANDPASTE}
  179. procedure ClearClipboardBuffer;
  180. {$ENDIF}
  181.  
  182. var
  183.    MemoVars: MemoSet;
  184.  
  185. {+++++++++++++++++++++++++++++} IMPLEMENTATION {+++++++++++++++++++++++++++++}
  186. const
  187.   NilLine: string[6] = ' gold ';
  188.  
  189. {$IFDEF CUTANDPASTE}
  190. var
  191.   Marking: boolean;
  192.   AtBlockStart,
  193.   AtBlockEnd: boolean;
  194. {$ENDIF}
  195.  
  196. procedure MemoSetError(ECode:integer);
  197. {}
  198. {$IFOPT D+}
  199. var Msg: string;
  200. {$ENDIF}
  201. begin
  202.    MemoVars.LastEcode := ECode;
  203. {$IFOPT D+}
  204.    case ECode of
  205.       1001 : Msg := 'Unable to create the edit window';
  206.       0: exit;
  207.    end; {case}
  208.    if PromptCustom(' GoldMemo Error ',Msg,' ~I~gnore ',' ~A~bort ','',279,286,0,0, 10000) = 2 then
  209.       Halt;
  210. {$ENDIF}
  211. end; {MemoSetError}
  212.  
  213. function LastMemoError: integer;
  214. {}
  215. begin
  216.    LastMemoError := MemoVars.LastECode;
  217. end; { LastMemoError }
  218.  
  219. procedure MemoWarning(ID:integer);
  220. {}
  221. begin
  222.    case ID of
  223.      1: PromptOK(MemoVars.ClipboardMsgTitle,MemoVars.ClipboardNoMemoryMsg);
  224.      2: PromptOK(MemoVars.ClipboardMsgTitle,MemoVars.ClipboardLowMemoryMsg);
  225.      3: PromptOK(MemoVars.WarningTitle,MemoVars.WordwrapoffMsg);
  226.      4: PromptOK(MemoVars.WarningTitle,MemoVars.ClipboardLineFullMsg);
  227.      5: PromptOK(MemoVars.WarningTitle,MemoVars.MaxLinesMsg);
  228.      6: PromptOK(MemoVars.WarningTitle,MemoVars.MemoNearlyFullMsg);
  229.    end;
  230. end; { MemoWarning }
  231.  
  232.                     {**********************************}
  233.                     {**  Generic Callback Functions  **}
  234.                     {**********************************}
  235.  
  236. {$IFOPT F-}
  237.    {$DEFINE FOFF}
  238.    {$F+}
  239. {$ENDIF}
  240.  
  241. procedure NoMemoCharHook(MP:MemoCfgPtr;var Code:word; var X,Y:byte);
  242. {}
  243. begin
  244. end; { NoMemoCharHook }
  245.  
  246. procedure NoMemoHindHook(MP:MemoCfgPtr);
  247. {}
  248. begin
  249. end; { NoMemoHindHook }
  250.  
  251. function DummyGetLine(MP:MemoCfgPtr;LineNum: longint): string;
  252. {abstract}
  253. begin
  254.    DummyGetLine := '';
  255. end; { DummyGetLine }
  256.  
  257. procedure DummySetLine(MP:MemoCfgPtr;LineNum: longint;Str:string);
  258. {abstract}
  259. begin
  260. end; { DummySetLine }
  261.  
  262. procedure DummyDelLine(MP:MemoCfgPtr;LineNum: longint);
  263. {abstract}
  264. begin
  265. end; { DummyDelLine }
  266.  
  267. function DummyInsLine(MP:MemoCfgPtr;LineNum: longint):longint;
  268. {abstract}
  269. begin
  270.    DummyInsLine := 0;
  271. end; { DummyInsLine }
  272.  
  273. procedure DummyInsProc(Insert:boolean);
  274. {}
  275. begin
  276.    if Insert then
  277.       CursorOn
  278.    else
  279.       CursorFull;
  280. end; { DummyInsProc }
  281.  
  282.                       {******************************}
  283.                       {**  SLL Callback Functions  **}
  284.                       {******************************}
  285.  
  286. function SLLGetLine(MP:MemoCfgPtr;LineNum: longint): string;
  287. {}
  288. begin
  289.    SLLGetLine := _SLLGetNodeStr(SingleLL(MP^.DataSource^),_SLLNodePtr(SingleLL(MP^.DataSource^),LineNum),250);
  290. end; { SLLGetLine }
  291.  
  292. function SLLInsLine(MP:MemoCfgPtr;LineNum: longint):longint;
  293. {}
  294. begin
  295.    if LineNum > SingleLL(MP^.DataSource^).TotalNodes then
  296.    begin
  297.       if _SllInsStrBefore(SingleLL(MP^.DataSource^),nil,'') <> 0 then
  298.          {oh well}
  299.    end
  300.    else if _SllInsStrBefore(SingleLL(MP^.DataSource^),_SLLNodePtr(SingleLL(MP^.DataSource^),LineNum),'') <> 0 then
  301.       {oh well};
  302.    SLLInsLine := SingleLL(MP^.DataSource^).TotalNodes
  303. end; { SLLInsLine }
  304.  
  305. procedure SLLSetLine(MP:MemoCfgPtr;LineNum:longint;Str:string);
  306. {}
  307. begin
  308.    if LineNum = succ(MP^.TotalNodes) then {really adding a line}
  309.       if SLLInsLine(MP,LineNum) = 0 then
  310.          exit;
  311.    if _SLLChangeStr(SingleLL(MP^.DataSource^),_SLLNodePtr(SingleLL(MP^.DataSource^),LineNum),Str) <> 0 then
  312.      {oh well};
  313. end; { SLLSetLine }
  314.  
  315. procedure SLLDelLine(MP:MemoCfgPtr;LineNum: longint);
  316. {}
  317. begin
  318.    _SLLDelNode(SingleLL(MP^.DataSource^),_SLLNodePtr(SingleLL(MP^.DataSource^),LineNum));
  319. end; { SLLDelLine }
  320.  
  321.  
  322.                       {******************************}
  323.                       {**  DLL Callback Functions  **}
  324.                       {******************************}
  325.  
  326. function DLLGetLine(MP:MemoCfgPtr;LineNum: longint): string;
  327. {}
  328. begin
  329.    DLLGetLine := DLLGetNodeStr(DLLNodePtr(LineNum),0,0);
  330. end; { DLLGetLine }
  331.  
  332. procedure DLLSetLine(MP:MemoCfgPtr;LineNum:longint;Str:string);
  333. {}
  334. begin
  335.    if DLLChange(DLLNodePtr(LineNum),Str,succ(length(Str))) <> 0 then
  336.      {oh well};
  337. end; { DLLSetLine }
  338.  
  339. procedure DLLDelLine(MP:MemoCfgPtr;LineNum: longint);
  340. {}
  341. begin
  342.    DLLDelNode(DLLNodePtr(LineNum));
  343. end; { DLLDelLine }
  344.  
  345. function DLLInsLine(MP:MemoCfgPtr;LineNum: longint):longint;
  346. {}
  347. var Str: string;
  348. begin
  349.    Str := '';
  350.    if LineNum > LinkVars.ActiveDLL^.TotalNodes then
  351.    begin
  352.       if DLLInsertBefore(nil,Str,0) <> 0 then
  353.          {oh well}
  354.    end
  355.    else if DLLInsertBefore(DLLNodePtr(LineNum),Str,1) <> 0 then
  356.       {oh well};
  357.    DLLInsLine := LinkVars.ActiveDLL^.TotalNodes
  358. end; { DLLInsLine }
  359.  
  360.                    {********************************}
  361.                    {**  Array Callback Functions  **}
  362.                    {********************************}
  363.  
  364. function ArrayGetLine(MP:MemoCfgPtr;LineNum: longint): string;
  365. {}
  366. var W: longint;
  367.     TempStr: String;
  368.     ArrayOffset: word;
  369. begin
  370.    if (LineNum < 1) or (LineNum > MP^.MaxLines) then
  371.       ArrayGetLine := ''
  372.    else
  373.    begin
  374.       {move array string to Temp}
  375.       W := pred(LineNum) * succ(MP^.StrLength);
  376.       ArrayOffset := Ofs(MP^.DataSource^) + W;
  377.       move(Mem[Seg(MP^.DataSource^):ArrayOffset],TempStr,1);
  378.       move(Mem[Seg(MP^.DataSource^):succ(ArrayOffset)],TempStr[1],ord(TempStr[0]));
  379.       ArrayGetLine := TempStr;
  380.    end;
  381. end; { ArrayGetLine }
  382.  
  383. procedure ArraySetLine(MP:MemoCfgPtr;LineNum:longint;Str:string);
  384. {}
  385. var W: longint;
  386.     ArrayOffset: word;
  387.     Len: byte;
  388. begin
  389.    if (LineNum >= 1) and (LineNum <= MP^.MaxLines) then
  390.    begin
  391.       {move array string to Temp}
  392.       W := pred(LineNum) * succ(MP^.StrLength);
  393.       ArrayOffset := Ofs(MP^.DataSource^) + W;
  394.       Len := succ(length(Str));
  395.       if Len <= MP^.StrLength then
  396.          move(Str[0],mem[Seg(MP^.DataSource^):ArrayOffset],Len)
  397.       else
  398.       begin
  399.          Str := copy(Str,1,MP^.StrLength);
  400.          move(Str[0],mem[Seg(MP^.DataSource^):ArrayOffset],succ(length(Str)));
  401.       end;
  402.    end;
  403. end; { ArraySetLine }
  404.  
  405. procedure ArrayDelLine(MP:MemoCfgPtr;LineNum: longint);
  406. {}
  407. var W: longint;
  408.     ArrayOffset: word;
  409.     Null: char;
  410. begin
  411.    if (LineNum >= 1) and (LineNum < MP^.MaxLines) then
  412.    begin
  413.       W := pred(LineNum) * succ(MP^.StrLength);
  414.       ArrayOffset := Ofs(MP^.DataSource^) + W;
  415.       move(mem[Seg(MP^.DataSource^):ArrayOffset+succ(MP^.StrLength)],
  416.            Mem[Seg(MP^.DataSource^):ArrayOffset],
  417.            (MP^.MaxLines - LineNum)*succ(MP^.StrLength));
  418.       {empty last line}
  419.       W := pred(MP^.MaxLines) * succ(MP^.StrLength);
  420.       ArrayOffset := Ofs(MP^.DataSource^) + W;
  421.       Null := char(0);
  422.       move(Null,Mem[seg(MP^.DataSource^):ArrayOffset],1);
  423.    end;
  424. end; { ArrayDelLine }
  425.  
  426. function ArrayInsLine(MP:MemoCfgPtr;LineNum: longint):longint;
  427. {}
  428. var W: longint;
  429.     ArrayOffset: word;
  430.     Null: char;
  431. begin
  432.    if (LineNum >= 1) and (LineNum < MP^.MaxLines) then
  433.    begin
  434.       W := pred(LineNum) * succ(MP^.StrLength);
  435.       ArrayOffset := Ofs(MP^.DataSource^) + W;
  436.       move(mem[Seg(MP^.DataSource^):ArrayOffset],
  437.            Mem[Seg(MP^.DataSource^):ArrayOffset+succ(MP^.StrLength)],
  438.            (MP^.MaxLines - LineNum)*succ(MP^.StrLength));
  439.       {empty new line}
  440.       Null := char(0);
  441.       move(Null,Mem[seg(MP^.DataSource^):ArrayOffset],1);
  442.       if succ(MP^.TotalNodes) > MP^.MaxLines then
  443.          ArrayInsLine := MP^.MaxLines
  444.       else
  445.          ArrayInsLine := succ(MP^.TotalNodes);
  446.    end
  447.    else
  448.       ArrayInsLine := MP^.TotalNodes;
  449. end; { ArrayInsLine }
  450.  
  451. {$IFDEF FOFF}
  452.    {$F-}
  453.    {$UNDEF FOFF}
  454. {$ENDIF}
  455.  
  456. procedure InitMemoCfg(var MemoDetails: MemoCfg);
  457. {}
  458. var
  459.    A: TintElement;
  460.    I: integer;
  461. begin
  462.    fillchar(MemoDetails,sizeof(MemoDetails),#0);
  463.    with MemoDetails do
  464.    begin
  465.       DataSource := nil;
  466.       DataType := SourceUnknown;
  467.       LineStr := NilLine;
  468.       X1 := 1;
  469.       Y1 := 1;
  470.       X2 := 60;
  471.       Y2 := 15;
  472.       WiType := MemoVars.WType;
  473.       WStyle := MemoVars.WinStyle;
  474.       TotalNodes := 0;
  475.       TopNode := 0;
  476.       CursorPosX := 1;
  477.       TargetPosX := 0;
  478.       CursorPosY := 1;
  479.       BlockX1 := 1;
  480.       BlockY1 := 1;
  481.       BlockX2 := 1;
  482.       BlockY2 := 1;
  483.       FirstCharPos := 1;
  484.       MaxWidth := 120;
  485.       MaxLines := 0;
  486.       AllowEdits := true;
  487.       WordWrap := true;
  488.       InWindow := false;
  489.       DrawVScroll := true;
  490.       WarningGiven := false;
  491.       InsertOn := true;
  492.       UsingArray := false;
  493.       IsDirty := false;
  494.       for A := FirstMemoCol to LastMemoCol do
  495.          Col[A] := Tint[A];
  496.       GetLine := DummyGetLine;
  497.       SetLine := DummySetLine;
  498.       DelLine := DummyDelLine;
  499.       InsLine := DummyInsLine;
  500.       InsMode := DummyInsProc;
  501.       CharHook := NoMemoCharHook;
  502.       HindHook := NoMemoHindHook;
  503.       {header/footer stuff}
  504.       for I :=  1 to ListMaxHeaders do
  505.          Headers[I] := nil;
  506.       ScrollHeader := true;
  507.       for I :=  1 to ListMaxFooters do
  508.          Footers[I] := nil;
  509.       ScrollFooter := true;
  510.    end;
  511. end; { InitMemoCfg }
  512.  
  513. procedure MemoSetWordWrap(var MemoDetails: MemoCfg; On:boolean);
  514. {}
  515. begin
  516.    Memodetails.WordWrap := On;
  517. end; {MemoSetWordWrap}
  518.  
  519. procedure MemoSetDirty(var MemoDetails: MemoCfg; On:boolean);
  520. {}
  521. begin
  522.    Memodetails.IsDirty := On;
  523. end; {MemoSetWordWrap}
  524.  
  525. function MemoIsDirty(var MemoDetails: MemoCfg):boolean;
  526. {}
  527. begin
  528.    MemoIsDirty := Memodetails.IsDirty;
  529. end; {MemoSetWordWrap}
  530.  
  531. procedure MemoSetWin(var MemoDetails: MemoCfg; X1,Y1,X2,Y2:integer; Style:byte);
  532. {}
  533. begin
  534.    MemoDetails.WX1 := X1;
  535.    MemoDetails.WY1 := Y1;
  536.    MemoDetails.WX2 := X2;
  537.    MemoDetails.WY2 := Y2;
  538.    MemoDetails.WStyle := Style;
  539. end; { MemoSetWin }
  540.  
  541. procedure MemoSetGaps(var MemoDetails: MemoCfg; LeftGap,RightGap,BotGap,TopGap: byte);
  542. {}
  543. begin
  544.    MemoDetails.LeftGap := LeftGap;
  545.    MemoDetails.RightGap := RightGap;
  546.    MemoDetails.BotGap := BotGap;
  547.    MemoDetails.TopGap := TopGap;
  548. end; { MemoSetGaps }
  549.  
  550. procedure MemoSetColor(var MemoDetails: MemoCfg; A:TintElement;C:byte);
  551. {}
  552. begin
  553.    if A in [FirstMemoCol..LastMemoCol] then
  554.       MemoDetails.Col[A] := C;
  555. end; { MemoSetColor }
  556.  
  557. procedure MemoAssignHindHook(var MemoDetails: MemoCfg; Proc:MemoHindHook);
  558. {}
  559. begin
  560.    MemoDetails.HindHook := Proc;
  561. end; { MemoAssignHindHook }
  562.  
  563. procedure MemoAssignCharHook(var MemoDetails: MemoCfg; Proc:MemoCharHook);
  564. {}
  565. begin
  566.    MemoDetails.CharHook := Proc;
  567. end; { MemoAssignCharHook }
  568.  
  569. procedure MemoRemoveCharHook(var MemoDetails: MemoCfg);
  570. {}
  571. begin
  572.    MemoDetails.CharHook := NoMemoCharHook;
  573. end; { MemoRemoveCharHook }
  574.  
  575. procedure MemoRemoveHindHook(var MemoDetails: MemoCfg);
  576. {}
  577. begin
  578.    MemoDetails.HindHook := NoMemoHindHook;
  579. end; { MemoRemoveHindHook }
  580.  
  581. procedure MemoStoreActiveLine(var MemoDetails: MemoCfg);
  582. {}
  583. begin
  584.    with MemoDetails do
  585.         SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  586. end; {MemoStoreActiveLine}
  587.  
  588. procedure MemoAssignSLL(var MemoDetails: MemoCfg; var MemoSource: SingleLL);
  589. {}
  590. begin
  591.    InitMemoCfg(MemoDetails);
  592.    with MemoDetails do
  593.    begin
  594.       TotalNodes := MemoSource.TotalNodes;
  595.       TopNode := 1;
  596.       DataSource := @MemoSource;
  597.       DataType := SourceSLL;
  598.       GetLine := SLLGetLine;
  599.       SetLine := SLLSetLine;
  600.       DelLine := SLLDelLine;
  601.       InsLine := SLLInsLine;
  602.    end;
  603. end; { MemoAssignSLL }
  604.  
  605. procedure MemoReAssignSLL(var MemoDetails: MemoCfg; var MemoSource: SingleLL);
  606. begin
  607.    with MemoDetails do
  608.    begin
  609.       TotalNodes := MemoSource.TotalNodes;
  610.       TopNode := 1;
  611.       DataSource := @MemoSource;
  612.       LineStr := NilLine;
  613.    end;
  614. end; { MemoReAssignSLL }
  615.  
  616. procedure MemoAssignDLL(var MemoDetails: MemoCfg; var MemoSource: DoubleLL);
  617. {}
  618. begin
  619.    InitMemoCfg(MemoDetails);
  620.    with MemoDetails do
  621.    begin
  622.       TotalNodes := MemoSource.TotalNodes;
  623.       TopNode := 1;
  624.       DataSource := @MemoSource;
  625.       DataType := SourceDLL;
  626.       GetLine := DLLGetLine;
  627.       SetLine := DLLSetLine;
  628.       DelLine := DLLDelLine;
  629.       InsLine := DLLInsLine;
  630.    end;
  631. end; { MemoAssignDLL }
  632.  
  633. procedure MemoAssignArray(var MemoDetails: MemoCfg; var MemoSource; StrLen:Byte;ArrayElements:byte);
  634. {}
  635. begin
  636.    InitMemoCfg(MemoDetails);
  637.    with MemoDetails do
  638.    begin
  639.       UsingArray := true;
  640.       MaxLines := ArrayElements;
  641.       TotalNodes := ArrayElements;
  642.       TopNode := 1;
  643.       DataSource := @MemoSource;
  644.       DataType := SourceArray;
  645.       GetLine := ArrayGetLine;
  646.       SetLine := ArraySetLine;
  647.       DelLine := ArrayDelLine;
  648.       InsLine := ArrayInsLine;
  649.       StrLength := StrLen;
  650.    end;
  651. end; { MemoAssignArray }
  652.  
  653.                           {*********************}
  654.                           {**  Display Procs  **}
  655.                           {*********************}
  656. procedure MemoSetDirtyFlag(var MemoDetails: MemoCfg);
  657. {INTERNAL}
  658. begin
  659.    Memodetails.LineStr := NilLine;
  660. end; {MemoSetDirtyFlag}
  661.  
  662. function BlockActive(var MemoDetails:MemoCfg): boolean;
  663. {}
  664. begin
  665.    with MemoDetails do
  666.       BlockActive := (BlockY2 > BlockY1)
  667.                      or
  668.                      ((BlockX2 > BlockX1) and (BlockY1 = BlockY2));
  669. end; { BlockActive }
  670.  
  671. procedure MemoWriteVScrollBar(var MemoDetails:MemoCfg; Status:gStatus);
  672. {}
  673. var A: byte;
  674. begin
  675.    with MemoDetails do
  676.       if DrawVScroll then
  677.       begin
  678.          if (TotalNodes > succ(Y2-Y1)) or (TopNode > 1) then {need a scroll bar}
  679.          begin
  680.             if Status in [Activate,HiStatus] then
  681.                A := Col[MemoScrollbarHi]
  682.             else
  683.                A := Col[MemoScrollbarNorm];
  684.             WriteVScrollBar(X2,Y1,Y2,A,pred(TopNode)+CursorPosY,TotalNodes);
  685.          end else {clear the scroll bar area}
  686.          begin
  687.             if Status in [Activate,HiStatus] then
  688.                A := Col[MemoHi]
  689.             else
  690.                A := Col[MemoNorm];
  691.             WriteVert(X2,Y1,A,replicate(succ(Y2-Y1),' '));
  692.          end;
  693.       end;
  694. end; { MemoWriteVScrollBar }
  695.  
  696. procedure MemoWriteLineInBlock(var MemoDetails:MemoCfg;var Str:string;LineNum:longint);
  697. {The passed string is already padded and adjusted for the display window}
  698. var StartX,EndX: integer;   {block start X and block end X}
  699. begin
  700.    with MemoDetails do
  701.    begin
  702.       if  ((BlockY1 < LineNum) or (BlockX1 <= FirstCharPos))
  703.       and ((BlockY2 > LineNum) or (BlockX2 >= FirstCharPos + X2-X1)) then {whole visible line is part of block}
  704.           WriteAT(X1,Y1+LineNum-TopNode,Col[MemoBlock],
  705.                  padleft(copy(Str,FirstCharPos,255),succ(X2-X1) - ord(DrawVScroll),' '))
  706.       else     {part of line is in block}
  707.       begin
  708.          if (BlockY1 < LineNum) or (BlockX1 <= FirstCharPos) then
  709.             StartX := 1
  710.          else
  711.             StartX := BlockX1 - pred(FirstCharPos);
  712.          if (BlockY2 > LineNum) or (BlockX2 >= FirstCharPos+ X2-X1) then
  713.             EndX := FirstCharPos + succ(X2-X1)
  714.          else
  715.             EndX := BlockX2 - pred(FirstCharPos);
  716.          if StartX > 1 then {write the non block-part}
  717.             WriteAT(X1,Y1+LineNum-TopNode,Col[MemoHi],copy(Str,1,StartX));
  718.          WriteAT(pred(X1) + StartX,Y1+LineNum-TopNode,Col[MemoBlock],
  719.                  copy(Str,StartX,EndX - StartX));
  720.          if (EndX < FirstCharPos + X2-X1) then
  721.             WriteAT(pred(X1)+EndX,Y1+LineNum-TopNode,Col[MemoHi],
  722.                     copy(Str,EndX,X2-X1-EndX+2));
  723.       end;
  724.    end;
  725. end; { MemoWriteLineInBlock }
  726.  
  727. procedure MemoWriteLineStr(var MemoDetails:MemoCfg);
  728. {}
  729. var CursY: longint;
  730. begin
  731.    with MemoDetails do
  732.    begin
  733.       CursY := Pred(TopNode) + CursorPosY;
  734.       if BlockActive(MemoDetails) and (BlockY1 <= CursY) and (BlockY2 >= CursY) then {this line is part of block}
  735.          MemoWriteLineInBlock(MemoDetails,LineStr,pred(TopNode+CursorPosY))
  736.       else
  737.         WriteAT(X1,Y1+pred(CursorPosY),Col[MemoHi],
  738.                 padleft(copy(LineStr,FirstCharPos,255),succ(X2-X1) - ord(DrawVScroll),' '));
  739.    end;
  740. end; { MemoWriteLineStr }
  741.  
  742. procedure MemoWriteLine(var MemoDetails:MemoCfg;LineNum:longint; Status:gStatus);
  743. {}
  744. var A: byte;
  745.     Str: string;
  746. begin
  747.    if LineNum < 1 then exit;
  748.    with MemoDetails do
  749.    begin
  750.       if Status in [Activate,HiStatus] then
  751.          A := Col[MemoHi]
  752.       else
  753.          A := Col[MemoNorm];
  754.       if LineNum = pred(TopNode) + CursorPosY then
  755.          Str := LineStr
  756.       else
  757.          Str := GetLine(@MemoDetails,LineNum);
  758.       Str := padleft(copy(Str,FirstCharPos,255),succ(X2-X1) - ord(DrawVScroll),' ');
  759.       if BlockActive(MemoDetails) and (BlockY1 <= LineNum) and (BlockY2 >= LineNum) then {this line is part of block}
  760.          MemoWriteLineInBlock(MemoDetails,Str,LineNum)
  761.       else
  762.          WriteAT(X1,Y1+LineNum-TopNode,A,Str);
  763.    end;
  764. end; { MemoWriteLine }
  765.  
  766. procedure MemoRefreshHeadFoot(var MemoDetails: MemoCfg);
  767. {}
  768. var
  769.    Counter,
  770.    I: integer;
  771.    TempStr: string;
  772.    W,X: byte;
  773. begin
  774.    with Memodetails do
  775.    begin
  776.       Counter := 0;
  777.       if Scrollheader then
  778.          X := FirstCharPos
  779.       else
  780.          X := 1;
  781.       W := (X2-X1)-ord(TotalNodes > succ(Y2-Y1));
  782.       for I := 1 to ListMaxHeaders do
  783.       begin
  784.          if Memodetails.Headers[I] <> nil then
  785.          begin
  786.             inc(Counter);
  787.             TempStr := copy(Memodetails.Headers[I]^,X,W);
  788.             if (TempStr <> '') and (TempStr[1] = '^') then
  789.             begin
  790.                delete(TempStr,1,1);
  791.                WriteBetween(succ(leftGap),X2-X1-RightGap,TopGap+Counter,Col[MemoHeaders],TempStr);
  792.             end
  793.             else
  794.                WriteAT(succ(leftGap),TopGap+Counter,Col[MemoHeaders],TempStr);
  795.          end;
  796.       end;
  797.       Counter := 0;
  798.       if ScrollFooter then
  799.          X := FirstCharPos
  800.       else
  801.          X := 1;
  802.       for I := 1 to ListMaxFooters do
  803.       begin
  804.          if Memodetails.Footers[I] <> nil then
  805.          begin
  806.             inc(Counter);
  807.             TempStr := copy(Memodetails.Footers[I]^,X,W);
  808.             if (TempStr <> '') and (TempStr[1] = '^') then
  809.             begin
  810.                delete(TempStr,1,1);
  811.                WriteBetween(succ(leftGap),X2-X1-RightGap,Y2+Counter,Col[MemoHeaders],TempStr);
  812.             end
  813.             else
  814.                WriteAT(succ(leftGap),Y2+Counter,Col[MemoHeaders],TempStr);
  815.          end;
  816.       end;
  817.    end;
  818. end; {MemoRefreshHeadFoot}
  819.  
  820. procedure DisplayMemo(var MemoDetails:MemoCfg; Status:gStatus);
  821. {}
  822. var I: integer;
  823. begin
  824.    MemoRefreshHeadFoot(Memodetails);
  825.    with MemoDetails do
  826.    begin
  827.       if LineStr = NilLine then
  828.       begin
  829.          TopNode := 1;
  830.          CursorPosY := 1;
  831.          case DataType of
  832.             SourceStrLL: TotalNodes := StringLL(DataSource^).TotalNodes;
  833.             SourceSLL: TotalNodes := SingleLL(DataSource^).TotalNodes;
  834.             SourceDLL: TotalNodes := DoubleLL(DataSource^).TotalNodes;
  835.          end; {case}
  836.          LineStr := GetLine(@Memodetails,1);
  837.       end;
  838.       for I := TopNode to TopNode + Y2 - Y1 do
  839.          MemoWriteLine(MemoDetails,I,Status);
  840.       {update scroll bars}
  841.       MemoWriteVScrollBar(MemoDetails,Status);
  842.    end;
  843. end; { DisplayMemo }
  844.  
  845. {$IFDEF CUTANDPASTE}
  846. procedure TurnBlockOff(var MemoDetails:MemoCfg);
  847. {}
  848. var WasActive: boolean;
  849. begin
  850.    WasActive := BlockActive(Memodetails);
  851.    with MemoDetails do
  852.    begin
  853.       BlockX2 := BlockX1;
  854.       BlockY2 := BlockY1;
  855.    end;
  856.    if WasActive then
  857.       DisplayMemo(MemoDetails,HiStatus);
  858. end; { TurnBlockOff }
  859. {$ELSE}
  860. procedure TurnBlockOff(var MemoDetails:MemoCfg);
  861. begin end;
  862. {$ENDIF}
  863.  
  864.                         {*************************}
  865.                         {**  Cursor Management  **}
  866.                         {*************************}
  867.  
  868. procedure MoveCursor(var MemoDetails: MemoCfg);
  869. {}
  870. var X,Y: byte;
  871. begin
  872.    with MemoDetails do
  873.    begin
  874.       X := CursorPosX + LeftGap;
  875.       Y := CursorPosY + TopGap + YH;
  876.       if InWindow then
  877.          gotoXY(X,Y)
  878.       else
  879.          gotoXY(pred(X1+X+pred(FirstCharPos)),pred(Y1+Y));
  880.       if DrawVScroll then
  881.          MemoWriteVScrollBar(MemoDetails, HiStatus);
  882.    end;
  883. end; { MoveCursor }
  884.  
  885. procedure CursorEnd(var MemoDetails: MemoCfg);
  886. {}
  887. var OldStart, NewPos: integer;
  888. begin
  889.    with MemoDetails do
  890.    begin
  891.       OldStart := FirstCharPos;
  892.       NewPos := length(LineStr) + ord(not Wordwrap);
  893.       if NewPos > MaxWidth then
  894.          NewPos := MaxWidth;
  895.       if NewPos < FirstCharPos then
  896.          FirstCharPos := 1
  897.       else if NewPos - pred(FirstCharPos) > (X2-X1) then
  898.          FirstCharPos := NewPos - (X2-X1) {+ ord(NewPos = MaxWidth)} + 1;
  899.       CursorPosX := NewPos - pred(FirstCharPos);
  900.       if pred(FirstCharPos) + CursorPosX > MaxWidth then
  901.          dec(CursorPosX);
  902.       if OldStart <> FirstCharPos then
  903.          DisplayMemo(Memodetails,HiStatus);
  904.    end;
  905.    MoveCursor(Memodetails);
  906. end; { CursorEnd }
  907.  
  908. procedure CursorHome(var MemoDetails: MemoCfg);
  909. {}
  910. begin
  911.    with MemoDetails do
  912.    begin
  913.       CursorPosX := 1;
  914.       if FirstCharPos > 1 then
  915.       begin
  916.          FirstCharPos := 1;
  917.          DisplayMemo(Memodetails,HiStatus);
  918.       end;
  919.       MoveCursor(Memodetails);
  920.    end;
  921. end; { CursorHome }
  922.  
  923. procedure CheckXandMove(var MemoDetails: MemoCfg);
  924. {}
  925. var RealPos: integer;
  926. begin
  927.    with MemoDetails do
  928.       if pred(FirstCharPos)+CursorPosX > length(LineStr) then
  929.          CursorEnd(MemoDetails)
  930.       else if CursorPosX >= (X2-X1) then
  931.       begin
  932.          RealPos := pred(FirstCharPos)+CursorPosX;
  933.          CursorPosX := (X2-X1);
  934.          FirstCharPos := RealPos - pred(CursorPosX);
  935.          DisplayMemo(Memodetails,HiStatus);
  936.          MoveCursor(MemoDetails);
  937.       end else
  938.          MoveCursor(MemoDetails);
  939. end; { CheckXandMove }
  940.  
  941. procedure CursorUp(var MemoDetails: MemoCfg);
  942. {}
  943. begin
  944.    with MemoDetails do
  945.    begin
  946.       if (CursorPosY = 1) and (TopNode = 1) then
  947.          exit;
  948.       if TargetPosX = 0 then
  949.          TargetPosX := pred(FirstCharPos) + CursorPosX;
  950.       CursorPosX := TargetPosX - pred(FirstCharPos);
  951.       if CursorPosY = 1 then
  952.       begin
  953.          if TopNode > 1 then
  954.          begin
  955.             SetLine(@MemoDetails,TopNode,LineStr);
  956.             dec(TopNode);
  957.             LineStr := GetLine(@MemoDetails,TopNode);
  958.             DisplayMemo(MemoDetails,HiStatus);
  959.             CheckXandMove(Memodetails);
  960.          end;
  961.       end else
  962.       begin
  963.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  964.          dec(CursorPosY);
  965.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  966.          CheckXandMove(Memodetails);
  967.       end;
  968.    end;
  969. end; { CursorUp }
  970.  
  971. procedure CursorDown(var MemoDetails: MemoCfg);
  972. {}
  973. begin
  974.    with MemoDetails do
  975.    begin
  976.       if TargetPosX = 0 then
  977.          TargetPosX := pred(FirstCharPos) + CursorPosX;
  978.       CursorPosX := TargetPosX - pred(FirstCharPos);
  979.       if pred(TopNode) + CursorPosY < TotalNodes then
  980.       begin
  981.          if CursorPosY < succ(Y2-Y1) then
  982.          begin
  983.             SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  984.             inc(CursorPosY);
  985.             LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  986.          end else
  987.          begin
  988.             SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  989.             inc(TopNode);
  990.             LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  991.             DisplayMemo(MemoDetails,HiStatus);
  992.          end;
  993.          CheckXandMove(Memodetails);
  994.       end;
  995.    end;
  996. end; { CursorDown }
  997.  
  998. procedure CursorLeft(var MemoDetails: MemoCfg);
  999. {}
  1000. begin
  1001.    with MemoDetails do
  1002.    if pred(FirstCharPos) + CursorPosX > 1 then
  1003.    begin
  1004.       if CursorPosX > 1 then
  1005.       begin
  1006.          dec(CursorPosX);
  1007.          MoveCursor(MemoDetails);
  1008.       end else
  1009.       begin
  1010.          dec(FirstCharPos);
  1011.          DisplayMemo(MemoDetails,HiStatus);
  1012.       end;
  1013.    end else
  1014.    if WordWrap and ((TopNode > 1) or (CursorPosY > 1)) then
  1015.    begin
  1016.       CursorUp(MemoDetails);
  1017.       CursorEnd(MemoDetails);
  1018.    end;
  1019. end; { CursorLeft }
  1020.  
  1021. procedure CursorRight(var MemoDetails: MemoCfg);
  1022. {}
  1023. begin
  1024.    with MemoDetails do
  1025.    if pred(FirstCharPos) + CursorPosX < length(LineStr) + ord(not WordWrap) then
  1026.    begin
  1027.       if pred(FirstCharPos) + CursorPosX < MaxWidth then
  1028.       begin
  1029.          if CursorPosX >= (X2-X1) then
  1030.          begin
  1031.             inc(FirstCharPos);
  1032.             DisplayMemo(MemoDetails,HiStatus);
  1033.          end else
  1034.             inc(CursorPosX);
  1035.          MoveCursor(MemoDetails);
  1036.       end;
  1037.    end else
  1038.    if WordWrap then
  1039.    begin
  1040.       if pred(TopNode) + CursorPosY < TotalNodes then
  1041.       begin
  1042.          CursorDown(MemoDetails);
  1043.          CursorHome(MemoDetails);
  1044.       end;
  1045.    end;
  1046. end; { CursorRight }
  1047.  
  1048. procedure CursorRightWord(var MemoDetails: MemoCfg);
  1049. {}
  1050. var OldX: byte;
  1051.     OldY: longint;
  1052.     SpacePassed: boolean;
  1053. begin
  1054.    with MemoDetails do
  1055.    begin
  1056.       SpacePassed := false;
  1057.       repeat
  1058.          if LineStr[pred(FirstCharPos)+CursorPosX] in [' ',MemoVars.EndofParaCode] then
  1059.             SpacePassed := true;
  1060.          OldX := pred(FirstCharPos)+CursorPosX;
  1061.          OldY := pred(TopNode) + CursorPosY;
  1062.          CursorRight(Memodetails);
  1063.       until ((OldX = pred(FirstCharPos)+CursorPosX) and (OldY = pred(TopNode) + CursorPosY))
  1064.         or (not(LineStr[pred(FirstCharPos)+CursorPosX] in [' ',MemoVars.EndofParaCode]) and SpacePassed);
  1065.       MoveCursor(MemoDetails);
  1066.    end;
  1067. end; { CursorRightWord }
  1068.  
  1069. procedure CursorLeftWord(var MemoDetails: MemoCfg);
  1070. {}
  1071. var OldX: byte;
  1072.     OldY: longint;
  1073.     CharacterPassed: boolean;
  1074. begin
  1075.    with MemoDetails do
  1076.    begin
  1077.       CharacterPassed := false;
  1078.       CursorLeft(MemoDetails);
  1079.       repeat
  1080.          if not (LineStr[pred(FirstCharPos)+CursorPosX] in [' ',MemoVars.EndofParaCode]) then
  1081.             CharacterPassed := true;
  1082.          OldX := pred(FirstCharPos)+CursorPosX;
  1083.          OldY := pred(TopNode) + CursorPosY;
  1084.          CursorLeft(Memodetails);
  1085.       until ((OldX = pred(FirstCharPos)+CursorPosX) and (OldY = pred(TopNode) + CursorPosY))
  1086.          or ((LineStr[pred(FirstCharPos)+CursorPosX] in [' ',MemoVars.EndofParaCode]) and CharacterPassed);
  1087.       if not ((FirstCharPos =1) and (CursorPosX = 1) and (TopNode = 1) and ((CursorPosY = 1) or not WordWrap)) then
  1088.          CursorRightWord(Memodetails);
  1089.       MoveCursor(MemoDetails);
  1090.    end;
  1091. end; { CursorLeftWord }
  1092.  
  1093. procedure CursorPgUp(var MemoDetails: MemoCfg);
  1094. {}
  1095. begin
  1096.    with MemoDetails do
  1097.    begin
  1098.       if TopNode > 1 then
  1099.       begin
  1100.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1101.          dec(TopNode,succ(Y2-Y1));
  1102.          if TopNode < 1 then
  1103.             TopNode := 1;
  1104.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1105.          DisplayMemo(MemoDetails,HiStatus);
  1106.       end else
  1107.       if CursorPosY <> 1 then
  1108.       begin
  1109.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1110.          CursorPosY := 1;
  1111.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1112.       end;
  1113.       CheckXandMove(Memodetails);
  1114.    end;
  1115. end; { CursorPgUp }
  1116.  
  1117. procedure CursorPgDn(var MemoDetails: MemoCfg);
  1118. {}
  1119. begin
  1120.    with MemoDetails do
  1121.    begin
  1122.       if pred(TopNode + succ(Y2-Y1)) < TotalNodes then
  1123.       begin
  1124.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1125.          inc(TopNode,succ(Y2-Y1));
  1126.          CursorPosY := 1;
  1127.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1128.          DisplayMemo(MemoDetails,HiStatus);
  1129.          CheckXandMove(Memodetails);
  1130.       end else
  1131.       if CursorPosY + pred(TopNode) < TotalNodes then
  1132.       begin
  1133.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1134.          CursorPosY := succ(Y2-Y1);
  1135.          if CursorPosY + pred(TopNode) > TotalNodes then
  1136.             CursorPosY := TotalNodes - pred(TopNode);
  1137.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1138.          CheckXandMove(Memodetails);
  1139.       end;
  1140.    end;
  1141. end; { CursorPgDn }
  1142.  
  1143. procedure CursorTop(var MemoDetails: MemoCfg);
  1144. {}
  1145. begin
  1146.    with MemoDetails do
  1147.    begin
  1148.       if (CursorPosY <> 1) or (TopNode <> 1) then
  1149.       begin
  1150.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1151.          CursorPosY := 1;
  1152.          TopNode := 1;
  1153.          LineStr := GetLine(@MemoDetails,1);
  1154.          if FirstCharPos = 1 then
  1155.             DisplayMemo(MemoDetails,HiStatus);
  1156.       end;
  1157.       CursorHome(MemoDetails);
  1158.    end;
  1159. end; { CursorTop }
  1160.  
  1161. procedure CursorBottom(var MemoDetails: MemoCfg);
  1162. {}
  1163. begin
  1164.    with MemoDetails do
  1165.    begin
  1166.       if TopNode + (X2 - X1) >= TotalNodes then
  1167.          CursorPgDn(Memodetails)
  1168.       else
  1169.       begin
  1170.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1171.          TopNode := TotalNodes - (Y2 - Y1);
  1172.          CursorPosY := succ(Y2-Y1);
  1173.          LineStr := GetLine(@MemoDetails,TotalNodes);
  1174.          if FirstCharPos = 1 then
  1175.             DisplayMemo(MemoDetails,HiStatus);
  1176.       end;
  1177.       CursorHome(MemoDetails);
  1178.    end;
  1179. end; { CursorBottom }
  1180.  
  1181.                         {*************************}
  1182.                         {**  Wrapping Routines  **}
  1183.                         {*************************}
  1184.  
  1185. {$IFDEF WORDWRAP}
  1186.  
  1187. function GetNextLinesLeadingSpaces(var MemoDetails: MemoCfg;var S1,S2: string; var LastLine:boolean): byte;
  1188. {Removes the spaces from the beginning of line two, and adds them to
  1189.  the end of line one}
  1190. var Counter: byte;
  1191. begin
  1192.    counter := 0;
  1193.    if S2 = '' then
  1194.       S2 := MemoVars.EndofParaCode;
  1195.    while (S2 <> (MemoVars.EndofParaCode))
  1196.      and (S2[1] = ' ')
  1197.      and (length(S1) < MemoDetails.MaxWidth) do
  1198.    begin
  1199.        S1 := S1+' ';
  1200.        delete(S2,1,1);
  1201.        LastLine := false;
  1202.        inc(Counter);
  1203.        if S2 = '' then
  1204.           S2 := MemoVars.EndofParaCode;
  1205.    end;
  1206.    GetNextLinesLeadingSpaces := counter;
  1207. end; { GetNextLinesLeadingSpaces }
  1208.  
  1209. procedure GetNextLinesFullWords(var MemoDetails: MemoCfg;var S1,S2: string;var LastLine:boolean; Line:integer);
  1210. var WordSize: byte;
  1211.     RoomLeft: integer;
  1212.     Finished: boolean;
  1213.     BytesMoved: byte;
  1214. begin
  1215.    Finished := false;
  1216.    BytesMoved := 0;
  1217.    with Memodetails do
  1218.    begin
  1219.       repeat
  1220.          inc(BytesMoved,GetNextLinesLeadingSpaces(Memodetails,S1,S2,LastLine));
  1221.          RoomLeft := MaxWidth - length(S1);
  1222.          if RoomLeft > 0 then
  1223.          begin
  1224.             WordSize := pos(' ',S2);
  1225.             if WordSize = 0 then
  1226.                WordSize := length(S2);
  1227.             if (WordSize > 0)
  1228.             and (WordSize <= RoomLeft) then
  1229.             begin
  1230.                S1 := S1 + copy(S2,1,WordSize);
  1231.                delete(S2,1,WordSize);
  1232.                inc(BytesMoved,WordSize);
  1233.                if S2 = '' then  {shift up the next line}
  1234.                begin
  1235.                   DelLine(@MemoDetails,succ(Line));
  1236.                   if succ(Line) <= Totalnodes then
  1237.                      dec(Totalnodes);  {RDA}
  1238.                   S2 := GetLine(@MemoDetails,succ(Line));
  1239.                end;
  1240.                if (S2 = '') and (Line < TotalNodes) then
  1241.                   S2 := MemoVars.EndofParaCode;
  1242.                if S1[Length(S1)] = MemoVars.EndofParaCode then
  1243.                begin
  1244.                   LastLine := true;
  1245.                   Finished := true;
  1246.                end else
  1247.                   LastLine := false;
  1248.            end else
  1249.                Finished := true;
  1250.          end else
  1251.             Finished := true;
  1252.       until Finished;
  1253.       if (BytesMoved > 0) and (succ(Line) = pred(TopNode) + CursorPosY) then {move cursor}
  1254.       begin
  1255.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1256.          if CursorPosX > BytesMoved then
  1257.             dec(CursorPosX,BytesMoved)
  1258.          else
  1259.          begin
  1260.             CursorUp(Memodetails);
  1261.             CursorPosX := length(S1) {- pred(BytesMoved)};
  1262.          end;
  1263.          MoveCursor(Memodetails);
  1264.       end;
  1265.    end;
  1266. end; { GetNextLinesFullWords }
  1267.  
  1268. procedure PushWordsToNextLine(var MemoDetails: MemoCfg;var S1,S2: string;var LastLine: boolean;
  1269.                               Line:integer; AddSpaces:boolean; var BytesMoved:byte);
  1270. {}
  1271. var L: byte;
  1272.     Counter: integer;
  1273. begin
  1274.    with MemoDetails do
  1275.    begin
  1276.       Counter := pos(MemoVars.EndofParaCode,S1);
  1277.       L := length(S1);
  1278.       if (L > 0) and (Counter = L) and (Counter <= MaxWidth) and not AddSpaces then
  1279.          LastLine := true
  1280.       else
  1281.       begin
  1282.          if (Counter = 0) or (Counter > MaxWidth) then  {no paragraph split}
  1283.          begin
  1284.             Counter := length(S1);
  1285.             repeat
  1286.                dec(Counter);
  1287.             until (Counter = 0) or ((S1[Counter] = ' ') and (Counter <= MaxWidth));
  1288.          end;
  1289.          if (Counter = 0) and (length(S1) > MaxWidth) then {no spaces so split word}
  1290.             Counter := MaxWidth;
  1291.          if ((S2 = MemoVars.EndofParaCode)
  1292.              and
  1293.              (Counter < Length(S1))
  1294.             )
  1295.             or
  1296.             ( length(S2) + length(S1)-Counter > pred(sizeof(S2))) then {insert a new line}
  1297.          begin
  1298.             TotalNodes := InsLine(@MemoDetails,succ(Line));
  1299.             S2 := '';
  1300.          end;
  1301.          if  AddSpaces
  1302.          and (S1[Length(S1)] <> ' ')
  1303.          and (S1[Length(S1)] <> MemoVars.EndofParaCode)
  1304.          and (S2 <> MemoVars.EndofParaCode)
  1305.          and (S2 <> '')   then
  1306.             insert(' ',S2,1);
  1307.          insert(copy(S1,succ(Counter),length(S1)-Counter),S2,1);
  1308.          BytesMoved := length(S1)-Counter;
  1309.          delete(S1,succ(Counter),length(S1)-Counter);
  1310.          if length(S2) > MaxWidth then
  1311.             Lastline := false;
  1312.       end;
  1313.    end;
  1314. end; { PushWordsToNextLine }
  1315.  
  1316. procedure WrapFrom(var MemoDetails: MemoCfg;Line:longint;Paragraphs:word);
  1317. {}
  1318. var S1,S2: string;
  1319.     ParasWrapped : word;
  1320.     LastLine: boolean;
  1321.     I: integer;
  1322.     BytesMovedDown: byte;
  1323.     LastLineLen: byte;
  1324.  
  1325.    function GetString(TheLine:longint): string;
  1326.    {}
  1327.    begin
  1328.       with MemoDetails do
  1329.       if TheLine = pred(TopNode) + CursorPosY then  {active line}
  1330.          GetString := LineStr
  1331.       else
  1332.       begin
  1333.          if (TheLine > MaxLines) and (MaxLines <> 0) then
  1334.          begin
  1335.             ParasWrapped := Paragraphs;    {time to quit}
  1336.             GetString := '';
  1337.          end
  1338.          else if TheLine > TotalNodes then {insert a line}
  1339.          begin
  1340.             TotalNodes := InsLine(@MemoDetails,TheLine);
  1341.             GetString := '';
  1342.          end
  1343.          else                              {just get the line}
  1344.             GetString := GetLine(@MemoDetails,TheLine);
  1345.       end;
  1346.    end; { GetString }
  1347.  
  1348.    procedure CheckLastLine;
  1349.    {}
  1350.    begin
  1351.       if LastLine then
  1352.       begin
  1353.          LastLine := false;
  1354.          inc(ParasWrapped);
  1355.          if Line = Memodetails.TotalNodes then
  1356.             ParasWrapped := Paragraphs;
  1357.       end;
  1358.    end; { CheckLastLine }
  1359.  
  1360. begin
  1361.    if Memodetails.WordWrap then with MemoDetails do
  1362.    begin
  1363.       LastLineLen := length(GetLine(@MemoDetails,MaxLines)); {get very last line}
  1364.       if Line < 1 then
  1365.          Line := 1;
  1366.       if (Line >= MaxLines) and (MaxLines <> 0) then {nowhere to wrap!}
  1367.       begin
  1368.          if Line = pred(TopNode) + CursorPosY then
  1369.          begin
  1370.             if length(LineStr) > MaxWidth then
  1371.                LineStr := copy(LineStr,1,MaxWidth);
  1372.             SetLine(@MemoDetails,CursorPosY,LineStr);
  1373.             MemoWriteLine(MemoDetails,pred(TopNode) + CursorPosY,HiStatus);
  1374.          end;
  1375.       end else if not ((TotalNodes = 1) and (length(GetString(1)) <= MaxWidth)) then
  1376.       begin
  1377.          S1 := GetString(Line);
  1378.          S2 := GetString(succ(Line));
  1379.          ParasWrapped := 0;
  1380.          repeat
  1381.             LastLine := true;
  1382.             if (length(S1) > MaxWidth)
  1383.             or (pos(MemoVars.EndofParaCode,S1) > 0)  then   {line must be truncated}
  1384.             begin
  1385.                PushWordsToNextLine(MemoDetails,S1,S2,LastLine,Line,true,BytesMovedDown);
  1386.                SetLine(@MemoDetails,Line,S1);
  1387.                CheckLastLine;
  1388.                if ParasWrapped < Paragraphs then
  1389.                begin
  1390.                   inc(Line);
  1391.                   S1 := S2;
  1392.                   S2 := GetString(succ(Line));
  1393.                end
  1394.                else if S2 <> '' then
  1395.                begin
  1396.                   if Line = TotalNodes then
  1397.                      TotalNodes := InsLine(@MemoDetails,succ(Line));
  1398.                   SetLine(@MemoDetails,succ(Line),S2);
  1399.                end;
  1400.             end
  1401.             else            {line might be expanded}
  1402.             begin
  1403.                if S2 = '' then
  1404.                begin
  1405.                   Lastline := true;
  1406.                   ParasWrapped := Paragraphs;
  1407.                   SetLine(@MemoDetails,Line,S1);
  1408.                end else
  1409.                begin
  1410.                   LastLine := false;
  1411.                   if S1 <> '' then
  1412.                      GetNextLinesFullWords(Memodetails,S1,S2,LastLine,Line);
  1413.                   SetLine(@MemoDetails,Line,S1);
  1414.                   CheckLastLine;
  1415.                   if ParasWrapped < Paragraphs then
  1416.                   begin
  1417.                      inc(Line);
  1418.                      S1 := S2;
  1419.                      S2 := GetLine(@MemoDetails,succ(Line));
  1420.                   end
  1421.                   else if succ(Line) <= TotalNodes then
  1422.                      SetLine(@MemoDetails,succ(Line),S2);
  1423.                end;
  1424.             end;
  1425.          until ParasWrapped = Paragraphs;
  1426.          if (Line >= pred(TotalNodes))   {strip a trailing empty line}
  1427.          and (S2 = '') then
  1428.          begin
  1429.             S2 := GetLine(@MemoDetails,TotalNodes);
  1430.             if S2 = '' then
  1431.             begin
  1432.                DelLine(@MemoDetails,TotalNodes);
  1433.                dec(TotalNodes);
  1434.             end;
  1435.          end;
  1436.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1437.          if (CursorPosY > 1) and (Line >= TopNode) then
  1438.             MemoWriteLine(Memodetails,pred(TopNode)+pred(CursorPosY),HiStatus);
  1439.          for I := CursorPosY to succ(Y2-Y1) do
  1440.            MemoWriteLine(Memodetails,pred(TopNode)+I,HiStatus)
  1441.       end;
  1442.       {check to see if text may be pushed off the end}
  1443.       if (MaxLines <> 0)
  1444.       and (TotalNodes = MaxLines)
  1445.       and (pred(TopNode)+CursorPosY <> MaxLines)
  1446.       and (LastLineLen < length(GetLine(@MemoDetails,MaxLines)))
  1447.       and not WarningGiven then
  1448.       begin
  1449.          MemoWarning(6);
  1450.          WarningGiven := true;
  1451.       end;
  1452.       if TotalNodes < MaxLines then
  1453.          WarningGiven := false;
  1454.    end;
  1455. end; { WrapFrom }
  1456.  
  1457.  
  1458. procedure WrapFullEngine(var MemoDetails: MemoCfg;AddSpaces:boolean);
  1459. {Call this method to word wrap text before displaying it. This saves
  1460.  you the chore of inititally wordwrapping the default text.}
  1461. var S1,S2: string;
  1462.     LastLine: boolean;
  1463.     Line : integer;
  1464.     P,BytesMovedDown: byte;
  1465. begin
  1466.    if Memodetails.WordWrap then with MemoDetails do
  1467.    begin
  1468.       Line := 1;
  1469.       LastLine := false;
  1470.       S1 := GetLine(@MemoDetails,1);
  1471.       S2 := GetLine(@MemoDetails,2);
  1472. (*
  1473.       repeat
  1474.           P := pos(MemoVars.EndofParaCode,S1);
  1475.           if (length(S1) > MaxWidth) or ( (P > 0) and (P < length(S1))) then
  1476.              PushWordsToNextLine(MemoDetails,S1,S2,LastLine,Line,AddSpaces,BytesMovedDown)
  1477.           else
  1478.              if (S1 <> '') and (S1[length(S1)] <> MemoVars.EndofParaCode) then
  1479.                 GetNextLinesFullWords(MemoDetails,S1,S2,LastLine,Line);
  1480.           SetLine(@MemoDetails,Line,S1);
  1481.           inc(Line);
  1482.           if (MaxLines = 0) or (Line <= MaxLines) then
  1483.           begin
  1484.              S1 := S2;
  1485.              if (succ(Line) > TotalNodes)
  1486.              and (length(S1) > MaxWidth) then
  1487.              begin
  1488.                 S2 := '';
  1489.                 TotalNodes := InsLine(@MemoDetails,succ(TotalNodes));
  1490.              end else
  1491.                S2 := GetLine(@MemoDetails,succ(Line));
  1492.           end;
  1493.       until ((MaxLines <> 0) and (Line > MaxLines))
  1494.          or ((length(S1) <= MaxWidth) and (Line > TotalNodes));
  1495. *)
  1496.       P := pos(MemoVars.EndofParaCode,S1);
  1497.       repeat
  1498.           if (length(S1) > MaxWidth) or ( (P > 0) and (P < length(S1))) then
  1499.              PushWordsToNextLine(MemoDetails,S1,S2,LastLine,Line,AddSpaces,BytesMovedDown)
  1500.           else
  1501.              if (S1 <> '') and (S1[length(S1)] <> MemoVars.EndofParaCode) then
  1502.                 GetNextLinesFullWords(MemoDetails,S1,S2,LastLine,Line);
  1503.           SetLine(@MemoDetails,Line,S1);
  1504.           inc(Line);
  1505.           if (MaxLines = 0) or (Line <= MaxLines) then
  1506.           begin
  1507.              S1 := S2;
  1508.              if (succ(Line) > TotalNodes)
  1509.              and (length(S1) > MaxWidth) then
  1510.              begin
  1511.                 S2 := '';
  1512.                 TotalNodes := InsLine(@MemoDetails,succ(TotalNodes));
  1513.              end else
  1514.                S2 := GetLine(@MemoDetails,succ(Line));
  1515.           end;
  1516.           P := pos(MemoVars.EndofParaCode,S1);
  1517.           case DataType of
  1518.              SourceSLL: TotalNodes := SingleLL(MemoDetails.DataSource^).TotalNodes;
  1519.              SourceDLL: TotalNodes := DoubleLL(MemoDetails.DataSource^).TotalNodes;
  1520.           end;
  1521.       until ((MaxLines <> 0) and (Line > MaxLines))
  1522.          or (     (length(S1) <= MaxWidth)
  1523.               and (Line > TotalNodes)
  1524.               and ((P = 0) or (P = length(S1)))
  1525.             );
  1526.       SetLine(@MemoDetails,Line,copy(S1,1,MaxWidth));
  1527.       LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1528.       {finally strip all empty lines from the bottom}
  1529.       case DataType of
  1530.          SourceSLL: TotalNodes := SingleLL(MemoDetails.DataSource^).TotalNodes;
  1531.          SourceDLL: TotalNodes := DoubleLL(MemoDetails.DataSource^).TotalNodes;
  1532.       end;
  1533.       if DataType <> SourceArray then
  1534.       begin
  1535.          repeat
  1536.             if DataType = SourceSLL then
  1537.                Line := SingleLL(MemoDetails.DataSource^).TotalNodes
  1538.             else if DataType = SourceDLL then
  1539.                Line := DoubleLL(MemoDetails.DataSource^).TotalNodes;
  1540.             S1 := GetLine(@MemoDetails,Line);
  1541.             if S1 = '' then
  1542.             begin
  1543.                DelLine(@MemoDetails,Line);
  1544.                dec(TotalNodes);
  1545.             end;
  1546.          until (TotalNodes <= 1) or (S1 <> '');
  1547.          {!!make sure last line includes a MemoVars.EndofParaCode}
  1548.       end;
  1549.    end;
  1550. end; { WrapFullEngine }
  1551.  
  1552. procedure WrapFull(var MemoDetails: MemoCfg);
  1553. {}
  1554. begin
  1555.    WrapFullEngine(memodetails,true);
  1556. end; {WrapFull}
  1557.  
  1558. procedure WrapFullNoSpaces(var MemoDetails: MemoCfg);
  1559. {}
  1560. begin
  1561.    WrapFullEngine(memodetails,false);
  1562. end; {WrapFullNoSpaces}
  1563.  
  1564.  
  1565. {$ENDIF}
  1566.  
  1567. procedure RemoveTrailingLines(var MemoDetails: MemoCfg);
  1568. {}
  1569. var TempStr: string;
  1570.  
  1571.    function EmptyLine: boolean;
  1572.    {}
  1573.    begin
  1574.        EmptyLine :=  ((TempStr = MemoVars.EndofParaCode)
  1575.                       or
  1576.                       (TempStr = '')
  1577.                      );
  1578.    end; { EmptyLine }
  1579.  
  1580. begin
  1581.    with MemoDetails do
  1582.    begin
  1583.       repeat
  1584.          TempStr := GetLine(@MemoDetails,TotalNodes);
  1585.          if EmptyLine then
  1586.          begin
  1587.             DelLine(@MemoDetails,TotalNodes);
  1588.             dec(TotalNodes);
  1589.          end;
  1590.       until (TotalNodes <= 1) or not EmptyLine;
  1591.    end;
  1592. end; { RemoveTrailingLines }
  1593.  
  1594.                          {**********************}
  1595.                          {**  Key Management  **}
  1596.                          {**********************}
  1597.  
  1598. {$IFDEF WORDWRAP}
  1599. procedure WrapDeleteChar(var MemoDetails: MemoCfg);
  1600. {}
  1601. var
  1602.   I : integer;
  1603.   S1,S2: string;
  1604.   Dummy,
  1605.   WasASpace: boolean;
  1606.   BytesMoved: byte;
  1607. begin
  1608.    with MemoDetails do
  1609.    begin
  1610.       if not  ( (   ((LineStr = '') or (LineStr = MemoVars.EndofParaCode))
  1611.                        and (CursorPosY = 1)
  1612.                        and (TopNode = 1)
  1613.                        and (TotalNodes = 1)
  1614.                 )
  1615.                 or
  1616.                 (   (pred(TopNode)+CursorPosY = TotalNodes)
  1617.                     and (pred(FirstCharPos+CursorPosX) = length(LineStr))
  1618.                 )
  1619.               )  then
  1620.       begin
  1621.          Memodetails.IsDirty := true;
  1622.          TurnBlockOff(memodetails);
  1623.          if LineStr = MemoVars.EndofParaCode then
  1624.          begin
  1625.             DelLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1626.             dec(TotalNodes);
  1627.             if pred(TopNode)+CursorPosY > TotalNodes then
  1628.                CursorLeft(Memodetails);
  1629.             LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1630.             for I := pred(TopNode) + CursorPosY to TopNode + Y2 - Y1 do
  1631.                MemoWriteLine(MemoDetails,I,HiStatus);
  1632.          end else
  1633.          begin
  1634.             {check to see if deleting space at end of line}
  1635.             WasASpace := (CursorPosX = length(LineStr)) and (LineStr[length(LineStr)] = ' ');
  1636.             delete(LineStr,pred(FirstCharPos) + CursorPosX,1);
  1637.             SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1638.             if WasASpace then  {need to join last word with next line}
  1639.             begin
  1640.                I := pred(TopNode) + CursorPosY;
  1641.                S1 := GetLine(@MemoDetails,I);
  1642.                S2 := GetLine(@MemoDetails,Succ(I));
  1643.                PushWordsToNextLine(MemoDetails,S1,S2,Dummy,I,false,BytesMoved);
  1644.                if S1 = '' then {delete the line}
  1645.                begin
  1646.                   DelLine(@MemoDetails,I);
  1647.                   dec(TotalNodes);
  1648.                   SetLine(@MemoDetails,I,S2);
  1649.                end else
  1650.                begin
  1651.                   SetLine(@MemoDetails,I,S1);
  1652.                   SetLine(@MemoDetails,succ(I),S2);
  1653.                   inc(CursorPosY);
  1654.                end;
  1655.                CursorHome(Memodetails);
  1656.                CursorPosX := succ(BytesMoved);
  1657.                MoveCursor(Memodetails);
  1658.                LineStr := S2;
  1659.                WrapFrom(MemoDetails,I,2);
  1660.             end else
  1661.                WrapFrom(MemoDetails,pred(TopNode) + pred(CursorPosY),2);
  1662.          end;
  1663.       end;
  1664.    end;
  1665. end; { WrapDeleteChar }
  1666.  
  1667. procedure WrapProcessEnter(var MemoDetails: MemoCfg);
  1668. {splits the line at the cursor, and inserts an end of paragraph marker}
  1669. var
  1670.   PrevLine,CarryOver: string;
  1671. begin
  1672.    with MemoDetails do
  1673.    begin
  1674.       if (MaxLines = 0) or (TotalNodes < MaxLines) then {not last line}
  1675.       begin
  1676.          Memodetails.IsDirty := true;
  1677.          TurnBlockOff(memodetails);
  1678.          CarryOver := copy(LineStr,pred(FirstCharPos)+CursorPosX,length(LineStr)-pred(CursorPosX));
  1679.          delete(LineStr,CursorPosX,255);
  1680.          LineStr := LineStr + MemoVars.EndofParaCode;
  1681.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1682.          TotalNodes := InsLine(@MemoDetails,TopNode+CursorPosY);
  1683.          SetLine(@MemoDetails,TopNode+CursorPosY,CarryOver);
  1684.          if FirstCharPos = 1 then
  1685.             MemoWriteLine(MemoDetails,TopNode+CursorPosY-2,HiStatus);
  1686.          LineStr := CarryOver;
  1687.          PrevLine := GetLine(@MemoDetails,topNode+CursorPosY-2);
  1688.          inc(CursorPosY);
  1689.          if PrevLine[length(PrevLine)] = MemoVars.EndofParaCode then
  1690.             WrapFrom(MemoDetails,pred(TopNode + CursorPosY)-2,3)
  1691.          else
  1692.             WrapFrom(MemoDetails,pred(TopNode + CursorPosY)-2,2);
  1693.          CursorUp(MemoDetails);
  1694.          CursorRight(MemoDetails);
  1695.          CursorPosX := 1;
  1696.          MoveCursor(MemoDetails);
  1697.          if FirstCharPos = 1 then
  1698.             MemoWriteLine(MemoDetails,TopNode+CursorPosY-2,HiStatus)
  1699.          else
  1700.          begin
  1701.             FirstCharPos := 1;
  1702.             DisplayMemo(MemoDetails,HiStatus);
  1703.          end;
  1704.       end else  {no room to insert}
  1705.          MemoWarning(5);
  1706.    end;
  1707. end; { WrapProcessEnter }
  1708.  
  1709. procedure WrapInsertChar(var MemoDetails: MemoCfg;Ch:char);
  1710. {}
  1711. var NewX: byte;
  1712. begin
  1713.    with MemoDetails do
  1714.    begin
  1715.       Memodetails.IsDirty := true;
  1716.       TurnBlockOff(memodetails);
  1717.       insert(Ch,LineStr,pred(FirstCharPos)+CursorPosX);
  1718.       if  (Ch = ' ')
  1719.       and (pos(' ',LineStr) = CursorPosX)
  1720.       and (CursorPosY <> 1) then {just entered first space on line}
  1721.       begin
  1722.          CursorRight(Memodetails);
  1723.          Wrapfrom(MemoDetails,pred(TopNode)+pred(CursorPosY),1);
  1724.       end else
  1725.       if length(LineStr) > MaxWidth then
  1726.       begin
  1727.          WrapFrom(MemoDetails,pred(TopNode)+CursorPosY,1);
  1728.          if CursorPosX > length(LineStr) then
  1729.          begin
  1730.             NewX := CursorPosX - pred(length(LineStr));
  1731.             CursorHome(MemoDetails);
  1732.             CursorDown(MemoDetails);
  1733.             CursorPosX := NewX;
  1734.             MoveCursor(MemoDetails);
  1735.          end else
  1736.             CursorRight(MemoDetails);
  1737.       end else  {just re-display the active line with the new char inserted}
  1738.       begin
  1739.          MemoWriteLineStr(MemoDetails);
  1740.          CursorRight(MemoDetails);
  1741.       end;
  1742.    end;
  1743. end; { WrapInsertChar }
  1744.  
  1745. procedure WrapOvertypeChar(var MemoDetails: MemoCfg;Ch:char);
  1746. {}
  1747. var NewX: byte;
  1748. begin
  1749.    with MemoDetails do
  1750.    begin
  1751.       Memodetails.IsDirty := true;
  1752.       TurnBlockOff(memodetails);
  1753.       if LineStr = '' then
  1754.          LineStr := Ch
  1755.       else if (CursorPosX <= length(LineStr)) then
  1756.          LineStr[pred(FirstCharPos) + CursorPosX] := Ch
  1757.       else
  1758.          LineStr := LineStr + Ch;
  1759.       if  ((Ch = ' ')
  1760.       and (pos(' ',LineStr) = CursorPosX)
  1761.       and (CursorPosY <> 1))
  1762.       or (pred(FirstCharPos) + CursorPosX > MaxWidth) then {just entered first space on line}
  1763.       begin
  1764.          CursorRight(Memodetails);
  1765.          Wrapfrom(MemoDetails,pred(TopNode)+pred(CursorPosY),1);
  1766.          if CursorPosX > length(LineStr) then
  1767.          begin
  1768.             NewX := CursorPosX - pred(length(LineStr));
  1769.             CursorHome(MemoDetails);
  1770.             CursorDown(MemoDetails);
  1771.             CursorPosX := NewX;
  1772.             MoveCursor(MemoDetails);
  1773.          end;
  1774.       end else
  1775.       begin
  1776.          MemoWriteLineStr(MemoDetails);
  1777.          CursorRight(MemoDetails);
  1778.       end;
  1779.    end;
  1780. end; { WrapOvertypeChar }
  1781.  
  1782. {$ENDIF}
  1783.  
  1784. procedure DeleteChar(var MemoDetails: MemoCfg);
  1785. {}
  1786. var
  1787.    I: integer;
  1788.    TempStr:string;
  1789. begin
  1790.    with MemoDetails do
  1791.    begin
  1792.       Memodetails.IsDirty := true;
  1793.       if LineStr = '' then {delete the line}
  1794.       begin
  1795.          DelLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1796.          dec(TotalNodes);
  1797.          if pred(TopNode)+CursorPosY > TotalNodes then
  1798.             CursorLeft(Memodetails);
  1799.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  1800.          for I := CursorPosY to Y2-Y1 do
  1801.             MemoWriteLine(MemoDetails,I,HiStatus);
  1802.       end else if pred(FirstCharPos) + CursorPosX <= length(LineStr) then
  1803.       begin
  1804.          delete(LineStr,pred(FirstCharPos) + CursorPosX,1);
  1805.          MemoWriteLineStr(MemoDetails);
  1806.       end else if pred(TopNode)+CursorPosY < TotalNodes then
  1807.       begin
  1808.          TempStr := GetLine(@MemoDetails,TopNode+CursorPosY);
  1809.          if length(TempStr) + length(LineStr) <= MaxWidth then
  1810.          begin
  1811.             LineStr := LineStr+TempStr;
  1812.             DelLine(@MemoDetails,TopNode+CursorPosY); {lineafter cursor}
  1813.             dec(TotalNodes);
  1814.             DisplayMemo(MemoDetails,HiStatus);
  1815.          end;
  1816.       end;
  1817.    end; {with}
  1818. end; { DeleteChar }
  1819.  
  1820. procedure InsertChar(var MemoDetails: MemoCfg;Ch:char);
  1821. {}
  1822. begin
  1823.    with MemoDetails do
  1824.    begin
  1825.       TurnBlockOff(memodetails);
  1826.       if length(LineStr) < MaxWidth then
  1827.       begin
  1828.          Memodetails.IsDirty := true;
  1829.          insert(Ch,LineStr,pred(FirstCharPos)+CursorPosX);
  1830.          CursorRight(MemoDetails);
  1831.          MemoWriteLineStr(MemoDetails);
  1832.       end else
  1833.       begin
  1834.          Thunk;
  1835.          PromptOK('',MemoVars.LineFullMsg);
  1836.       end;
  1837.    end;
  1838. end; { InsertChar }
  1839.  
  1840. procedure OvertypeChar(var MemoDetails: MemoCfg;Ch:char);
  1841. {}
  1842. begin
  1843.    with MemoDetails do
  1844.    begin
  1845.       TurnBlockOff(memodetails);
  1846.       Memodetails.IsDirty := true;
  1847.       if LineStr = '' then
  1848.          LineStr := Ch
  1849.       else if (pred(FirstCharPos) + CursorPosX <= length(LineStr)) then
  1850.          LineStr[pred(FirstCharPos) + CursorPosX] := Ch
  1851.       else
  1852.          LineStr := LineStr + Ch;
  1853.       MemoWriteLineStr(MemoDetails);
  1854.       CursorRight(MemoDetails);
  1855.    end; {with}
  1856. end; { OvertypeChar }
  1857.  
  1858. procedure ProcessEnter(var MemoDetails: MemoCfg);
  1859. {}
  1860. var CarryOver: string;
  1861. begin
  1862.    if MemoDetails.WordWrap then
  1863.    begin
  1864. {$IFDEF WORDWRAP}
  1865.       WrapProcessEnter(MemoDetails);
  1866. {$ENDIF}
  1867.    end else
  1868.    with MemoDetails do   {split the line and be done with it!}
  1869.    begin
  1870.       if (MaxLines = 0) or (TotalNodes < MaxLines) then {not last line}
  1871.       begin
  1872.          Memodetails.IsDirty := true;
  1873.          TurnBlockOff(memodetails);
  1874.          CarryOver := copy(LineStr,pred(FirstCharPos)+CursorPosX,255);
  1875.          delete(LineStr,pred(FirstCharPos)+CursorPosX,255);
  1876.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  1877.          TotalNodes := InsLine(@MemoDetails,TopNode+CursorPosY);
  1878.          SetLine(@MemoDetails,TopNode+CursorPosY,CarryOver);
  1879.          CursorDown(MemoDetails);
  1880.          LineStr := CarryOver;
  1881.          CursorHome(MemoDetails);
  1882.          DisplayMemo(MemoDetails,HiStatus);
  1883.       end
  1884.       else  {no room to insert}
  1885.          MemoWarning(5);
  1886.    end;
  1887. end; {ProcessEnter}
  1888.  
  1889. procedure BackSpace(var MemoDetails: MemoCfg);
  1890. {}
  1891. var TempStr: string;
  1892. begin
  1893.    with MemoDetails do
  1894.    begin
  1895.       Memodetails.IsDirty := true;
  1896.       if (CursorPosX = 1) and (FirstCharPos = 1) and not Wordwrap then
  1897.       begin
  1898.          if not ((TopNode = 1) and (CursorPosY = 1)) then {join line with line above}
  1899.          begin
  1900.             TempStr := LineStr;
  1901.             CursorUp(Memodetails);
  1902.             CursorEnd(Memodetails);
  1903.             if length(TempStr) + length(LineStr) <= MaxWidth then
  1904.             begin
  1905.                LineStr := LineStr+TempStr;
  1906.                DelLine(@MemoDetails,TopNode+CursorPosY); {lineafter cursor}
  1907.                dec(TotalNodes);
  1908.                DisplayMemo(MemoDetails,HiStatus);
  1909.             end;
  1910.          end;
  1911.          exit;
  1912.       end;
  1913.       if  not (    (CursorPosX = 1)
  1914.                and (FirstCharPos = 1)
  1915.                and (CursorPosY = 1)
  1916.                and (TopNode = 1)
  1917.               ) then
  1918.       begin
  1919.          CursorLeft(Memodetails);
  1920. {$IFDEF WORDWRAP}
  1921.          if Wordwrap then
  1922.             WrapDeleteChar(Memodetails)
  1923.          else
  1924. {$ENDIF}
  1925.             DeleteChar(Memodetails);
  1926.       end;
  1927.    end;
  1928. end; { BackSpace }
  1929.  
  1930. procedure ProcessChar(var MemoDetails: MemoCfg;Ch:char);
  1931. {}
  1932. var NewX: byte;
  1933.     Finished : boolean;
  1934. begin
  1935.    with MemoDetails do
  1936.    begin
  1937.       if WordWrap then
  1938.       begin
  1939. {$IFDEF WORDWRAP}
  1940.          if not ((CursorPosX > MaxWidth) and (CursorPosY + pred(TopNode) = MaxLines)) then
  1941.          begin
  1942.             if InsertOn then
  1943.                WrapInsertChar(MemoDetails,Ch)
  1944.             else  {overtype mode}
  1945.                WrapOverTypeChar(MemoDetails,Ch);
  1946.          end;
  1947. {$ENDIF}
  1948.       end else {not in word wrap mode}
  1949.       begin
  1950.          if InsertOn then
  1951.             InsertChar(MemoDetails,Ch)
  1952.          else  {overtype mode}
  1953.             OverTypeChar(MemoDetails,Ch);
  1954.       end;
  1955.    end;
  1956. end;  { ProcessChar }
  1957.  
  1958. procedure MemoAssignHeader(var MemoDetails: MemoCfg; Line:byte; var Heading:string);
  1959. {}
  1960. begin
  1961.    if (Line < 1) or (Line > ListMaxHeaders) then
  1962.       MemoSetError(1003)
  1963.    else
  1964.       Memodetails.Headers[Line] := @Heading;
  1965. end; {MemoAssignHeader}
  1966.  
  1967. procedure MemoAssignFooter(var MemoDetails: MemoCfg; Line:byte; var Footnote:string);
  1968. {}
  1969. begin
  1970.    if (Line < 1) or (Line > ListMaxFooters) then
  1971.       MemoSetError(1003)
  1972.    else
  1973.       Memodetails.Footers[Line] := @Footnote;
  1974. end; {MemoAssignFooter}
  1975.  
  1976. procedure MemoRemoveHeader(var MemoDetails: MemoCfg; Line:byte);
  1977. {}
  1978. begin
  1979.    if (Line < 1) or (Line > ListMaxHeaders) then
  1980.       MemoSetError(1003)
  1981.    else
  1982.       Memodetails.Headers[Line] := nil;
  1983. end; {MemoRemoveHeader}
  1984.  
  1985. procedure MemoRemoveFooter(var MemoDetails: MemoCfg; Line:byte);
  1986. {}
  1987. begin
  1988.    if (Line < 1) or (Line > ListMaxFooters) then
  1989.       MemoSetError(1003)
  1990.    else
  1991.       Memodetails.Footers[Line] := nil;
  1992. end; {MemoRemoveFooter}
  1993.  
  1994. procedure MemoScrollHeader(var MemoDetails: MemoCfg; On:boolean);
  1995. {}
  1996. begin
  1997.    MemoDetails.ScrollHeader := On;
  1998. end; {MemoScrollHeader}
  1999.  
  2000. procedure MemoScrollFooter(var MemoDetails: MemoCfg; On:boolean);
  2001. {}
  2002. begin
  2003.    MemoDetails.ScrollFooter := On;
  2004. end; {MemoScrollFooter}
  2005.  
  2006. procedure SetInnerDimensions(var MemoDetails: MemoCfg);
  2007. {Asseses the window dimensions and sets the list coordinates
  2008.  X1..Y2 based on the window style and the gapxxx settings}
  2009. var
  2010.    Counter,
  2011.    I: integer;
  2012. begin
  2013.    with MemoDetails do
  2014.    begin
  2015.       X1 := 1 + LeftGap;
  2016.       Y1 := 1 + TopGap;
  2017.       X2 := WX2-succ(WX1)-2*ord(WStyle in [7,8]) - RightGap;
  2018.       Y2 := WY2-succ(WY1) - BotGap;
  2019.       {now adjust for the headers and footers}
  2020.       Counter := 0;
  2021.       for I := 1 to ListMaxHeaders do
  2022.          inc(Counter,ord(Memodetails.Headers[I] <> nil));
  2023.       YH := Counter;
  2024.       inc(Y1,Counter);
  2025.       Counter := 0;
  2026.       for I := 1 to ListMaxFooters do
  2027.          inc(Counter,ord(Memodetails.Footers[I] <> nil));
  2028.       dec(Y2,Counter);
  2029.       if Y2 <= Y1 then
  2030.          Y2 := Y1;
  2031.    end;
  2032. end; { SetInnerDimensions }
  2033.  
  2034.                          {************************}
  2035.                          {**  Block Management  **}
  2036.                          {************************}
  2037.  
  2038. {$IFDEF CUTANDPASTE}
  2039. procedure EraseBlock(var MemoDetails: MemoCfg);
  2040. {}
  2041. var I, WholeLineCount: integer;
  2042. begin
  2043.    if BlockActive(MemoDetails) then with MemoDetails do
  2044.    begin
  2045.       Memodetails.IsDirty := true;
  2046.       SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);  {save edits on cursor line}
  2047.       WholeLineCount := pred(BlockY2 - BlockY1) + ord(BlockX1 = 1);
  2048.       for I := 1 to WholelineCount do
  2049.          DelLine(@MemoDetails,BlockY1+ord(BlockX1 <> 1));
  2050.       {now delete the partial lines}
  2051.       if BlockY1 = BlockY2 then
  2052.       begin
  2053.          LineStr := GetLine(@MemoDetails,BlockY1);
  2054.          delete(LineStr,BlockX1,BlockX2 - BlockX1);
  2055.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2056.       end else
  2057.       begin
  2058.          if BlockX1 <> 1 then
  2059.          begin
  2060.             LineStr := GetLine(@MemoDetails,BlockY1);
  2061.             delete(LineStr,BlockX1,255);
  2062.             SetLine(@MemoDetails,BlockY1,LineStr);
  2063.          end;
  2064.          if BlockX2 <> 1 then
  2065.          begin
  2066.             LineStr := GetLine(@MemoDetails,BlockY2-WholeLineCount);
  2067.             delete(LineStr,1,pred(BlockX2));
  2068.             SetLine(@MemoDetails,BlockY2-WholeLineCount,LineStr);
  2069.          end;
  2070.       end;
  2071.       {move cursor to beginning of block, but make sure that area is
  2072.        visible in the display area}
  2073.       if WholeLineCount > 0 then
  2074.          dec(TotalNodes,WholeLineCount);
  2075.       if TopNode > BlockY1 then
  2076.          TopNode := BlockY1;
  2077.       CursorPosY := BlockY1 - pred(TopNode);
  2078.       CursorPosX := BlockX1 - pred(FirstCharPos);
  2079.       TurnBlockOff(Memodetails);
  2080.       LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2081. {$IFDEF WORDWRAP}
  2082.       if WordWrap then
  2083.          WrapFrom(MemoDetails,BlockY1-2,2);
  2084.       LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2085. {$ENDIF}
  2086.       CheckXandMove(Memodetails);
  2087.       DisplayMemo(Memodetails,HiStatus);
  2088.    end else
  2089.    if MemoVars.DelBlockKey = 339 then
  2090. {$IFDEF WORDWRAP}
  2091.       if Memodetails.WordWrap then
  2092.           WrapDeleteChar(MemoDetails)
  2093.       else
  2094. {$ENDIF}
  2095.           DeleteChar(MemoDetails)
  2096. end; { EraseBlock }
  2097.  
  2098.                        {***************************}
  2099.                        {**  Clipboard Functions  **}
  2100.                        {***************************}
  2101.  
  2102. procedure ClearClipboardBuffer;
  2103. {}
  2104. begin
  2105.    with MemoVars do
  2106.    begin
  2107.       if Clipboard <> nil then
  2108.       begin
  2109.          _SLLDestroy(ClipBoard^.LineList);
  2110.          freemem(Clipboard,sizeof(Clipboard^));
  2111.          ClipBoard := nil;
  2112.       end;
  2113.    end;
  2114. end; { ClearClipboardBuffer }
  2115.  
  2116. function CopyToClipboard(var MemoDetails:MemoCfg): integer;
  2117. {}
  2118. var RetCode: integer;
  2119.     TempStr: string;
  2120.     I: integer;
  2121. begin
  2122.    if BlockActive(MemoDetails) then with MemoDetails do
  2123.    begin
  2124.       ClearClipboardBuffer;  {empty the buffer first}
  2125.       if GoldMemAvail < sizeof(MemoVars.Clipboard^) then
  2126.       begin
  2127.          MemoWarning(1);
  2128.          CopyToClipBoard := 1;
  2129.       end else
  2130.       with MemoVars do
  2131.       begin
  2132.          SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);  {save edits on cursor line}
  2133.          TempStr := GetLine(@MemoDetails,BlockY1);
  2134.          getmem(ClipBoard,sizeof(Clipboard^));
  2135.          InitSLLStr(ClipBoard^.LineList);
  2136.          if BlockY1 = BlockY2 then  {one line or less}
  2137.          begin
  2138.             RetCode := _SLLAddStr(ClipBoard^.LineList,copy(TempStr,BlockX1,BlockX2 - BlockX1));
  2139.             ClipBoard^.TotalParagraphs := 0;
  2140.          end else
  2141.          begin
  2142.             TempStr := copy(TempStr,BlockX1,255); {get first line}
  2143.             RetCode := _SLLAddStr(ClipBoard^.LineList,TempStr);
  2144.             Clipboard^.TotalParagraphs := ord(pos(MemoVars.EndofParaCode,TempStr) > 0);
  2145.             Clipboard^.FullLastLine := (BlockX2 = 1);
  2146.             {we have to mess with the linked lists}
  2147.             for I := succ(BlockY1) to pred(BlockY2) do
  2148.                if Retcode = 0 then
  2149.                begin
  2150.                   TempStr := GetLine(@MemoDetails,I);
  2151.                   RetCode := _SLLAddStr(ClipBoard^.LineList,TempStr);
  2152.                   inc(Clipboard^.TotalParagraphs,ord(pos(MemoVars.EndofParaCode,TempStr) > 0));
  2153.                end;
  2154.             if BlockX2 <> 1 then
  2155.             begin
  2156.                TempStr := GetLine(@MemoDetails,BlockY2);
  2157.                RetCode := _SLLAddStr(ClipBoard^.LineList,copy(TempStr,1,pred(BlockX2)));
  2158.                inc(Clipboard^.TotalParagraphs,ord(pos(MemoVars.EndofParaCode,TempStr) > 0));
  2159.             end;
  2160.          end;
  2161.          CopyToClipBoard := ord(Retcode <> 0);
  2162.          if Retcode <> 0 then
  2163.             MemoWarning(2);    {only part of block copied to clipboard}
  2164.       end;
  2165.    end;
  2166. end; { CopyToClipboard }
  2167.  
  2168. procedure DelToClipboard(var MemoDetails: MemoCfg);
  2169. {}
  2170. begin
  2171.    if CopyToClipboard(Memodetails) = 0 then
  2172.       EraseBlock(Memodetails);
  2173. end; { DelToClipboard }
  2174.  
  2175. {$IFDEF WORDWRAP}
  2176.  
  2177. procedure WWInsFromClipboard(var MemoDetails: MemoCfg);
  2178. {}
  2179. var TempStr,CarryOver: string;
  2180.     TempList: SingleLL;
  2181.     NP: SingleNodePtr;
  2182.     StartLeft,StartX,StartY: integer;
  2183.     I, StartTop: longint;
  2184. begin
  2185.    with MemoDetails do
  2186.    with MemoVars do
  2187.       if (Clipboard <> nil) and not UsingArray then
  2188.       begin
  2189.          Memodetails.IsDirty := true;
  2190.          TurnBlockOff(MemoDetails);
  2191.          {record the starting cursor position}
  2192.          StartX := CursorPosX;
  2193.          StartY := CursorPosY;
  2194.          StartTop := TopNode;
  2195.          StartLeft := FirstCharPos;
  2196.          {split the line at the cursor position}
  2197.          if StartX <> 1 then
  2198.          begin
  2199.             CarryOver := copy(LineStr,pred(FirstCharPos)+CursorPosX,255);
  2200.             delete(LineStr,pred(FirstCharPos)+CursorPosX,255);
  2201.             SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2202.             inc(CursorPosY);
  2203.             TotalNodes := InsLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2204.             SetLine(@MemoDetails,pred(TopNode)+CursorPosY,CarryOver);
  2205.          end;
  2206.          {now insert all the lines from the clipboard}
  2207.          for I := ClipBoard^.LineList.TotalNodes downto 1 do
  2208.          begin
  2209.              LineStr := _SLLGetNodeStr(ClipBoard^.LineList,_SLLNodePtr(ClipBoard^.LineList,I),255);
  2210.              TotalNodes := InsLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2211.              SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2212.          end;
  2213.          {wordwrap the inserted text}
  2214.          WrapFrom(MemoDetails,pred(TopNode)+CursorPosY - 1,succ(Clipboard^.TotalParagraphs)+3);
  2215.          {restore cursor details}
  2216.          CursorPosX := StartX;
  2217.          CursorPosY := StartY;
  2218.          TopNode := StartTop;
  2219.          FirstCharPos := StartLeft;
  2220.          MoveCursor(Memodetails);
  2221.       end;
  2222. end; { WWInsFromClipboard }
  2223. {$ENDIF}  {WORDWRAP}
  2224.  
  2225. procedure InsFromClipboard(var MemoDetails: MemoCfg);
  2226. {}
  2227. var TempStr,CarryOver: string;
  2228.     TempList: SingleLL;
  2229.     NP: SingleNodePtr;
  2230.     StartLeft,StartX,StartY: integer;
  2231.     I, StartTop: longint;
  2232. begin
  2233.    with MemoDetails do
  2234.    with MemoVars do
  2235.       if (Clipboard <> nil) and not UsingArray then
  2236.       begin
  2237.          Memodetails.IsDirty := true;
  2238.          TurnBlockOff(MemoDetails);
  2239.          {record the starting cursor position}
  2240.          StartX := CursorPosX;
  2241.          StartY := CursorPosY;
  2242.          StartTop := TopNode;
  2243.          StartLeft := FirstCharPos;
  2244.          {get first line of clipboard}
  2245.          TempStr := _SLLGetNodeStr(ClipBoard^.LineList,_SLLNodePtr(ClipBoard^.LineList,1),255);
  2246.          if ClipBoard^.LineList.TotalNodes = 1 then {insert at cursor pos}
  2247.          begin
  2248.             if length(TempStr) + length(LineStr) > MaxWidth then
  2249.                MemoWarning(4)
  2250.             else
  2251.             begin
  2252.                insert(TempStr,LineStr,pred(FirstCharPos)+CursorPosX);
  2253.                SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2254.                MemoWriteLineStr(MemoDetails);
  2255.             end
  2256.          end else {multiple lines in clipboard}
  2257.          begin
  2258.             if pred(StartLeft) + StartX <> 1 then
  2259.             begin
  2260.                CarryOver := copy(LineStr,pred(FirstCharPos)+CursorPosX,255);
  2261.                if length(TempStr) + length(LineStr) - length(CarryOver) > MaxWidth then
  2262.                begin
  2263.                   MemoWarning(4);
  2264.                   exit;
  2265.                end else
  2266.                begin
  2267.                   delete(LineStr,pred(FirstCharPos)+CursorPosX,255);
  2268.                   LineStr := LineStr + TempStr;  {add first line of clipboard}
  2269.                   SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2270.                   if CarryOver <> '' then
  2271.                   begin
  2272.                      inc(CursorPosY);
  2273.                      TotalNodes := InsLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2274.                      SetLine(@MemoDetails,pred(TopNode)+CursorPosY,CarryOver);
  2275.                   end;
  2276.                end;
  2277.             end else
  2278.             begin
  2279.                TotalNodes := InsLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2280.                SetLine(@MemoDetails,pred(TopNode)+CursorPosY,TempStr);
  2281.             end;
  2282.             {now insert all the remaining lines from the clipboard}
  2283.             for I := 2 to ClipBoard^.LineList.TotalNodes do
  2284.             begin
  2285.                LineStr := _SLLGetNodeStr(ClipBoard^.LineList,_SLLNodePtr(ClipBoard^.LineList,I),255);
  2286.                inc(CursorPosY);
  2287.                TotalNodes := InsLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2288.                SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2289.             end;
  2290.             if (ClipBoard^.FullLastLine = false)
  2291.             and (pred(TopNode)+CursorPosY < TotalNodes) then {try to combine with next line}
  2292.             begin
  2293.                TempStr := GetLine(@MemoDetails,TopNode+CursorPosY);
  2294.                if (length(LineStr) + Length(TempStr) < MaxWidth) then
  2295.                begin
  2296.                   LineStr := LineStr+TempStr;
  2297.                   SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2298.                   DelLine(@MemoDetails,TopNode+CursorPosY);
  2299.                   dec(TotalNodes);
  2300.                end;
  2301.             end;
  2302.          end;
  2303.          {restore cursor details}
  2304.          CursorPosX := StartX;
  2305.          CursorPosY := StartY;
  2306.          TopNode := StartTop;
  2307.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2308.          FirstCharPos := StartLeft;
  2309.          MoveCursor(Memodetails);
  2310.          DisplayMemo(Memodetails,HiStatus);
  2311.       end;
  2312. end; { InsFromClipboard }
  2313. {$ENDIF}
  2314.  
  2315.                           {*********************}
  2316.                           {**  Block Marking  **}
  2317.                           {*********************}
  2318.  
  2319. {$IFDEF CUTANDPASTE}
  2320.  
  2321. procedure MarkBlockEnd(var MemoDetails: MemoCfg);
  2322. {}
  2323. var WasActive: boolean;
  2324. begin
  2325.    with MemoDetails do
  2326.    begin
  2327.       WasActive := BlockActive(MemoDetails);
  2328.       BlockX2 := pred(FirstCharPos) + CursorPosX;
  2329.       BlockY2 := pred(TopNode) + CursorPosY;
  2330.       if BlockActive(MemoDetails) then
  2331.          DisplayMemo(MemoDetails,HiStatus)
  2332.       else if WasActive then
  2333.          DisplayMemo(MemoDetails,HiStatus);
  2334.    end;
  2335. end; { MarkBlockEnd }
  2336.  
  2337. procedure MarkBlockStart(var MemoDetails: MemoCfg);
  2338. {}
  2339. var WasActive: boolean;
  2340. begin
  2341.    with MemoDetails do
  2342.    begin
  2343.       WasActive := BlockActive(MemoDetails);
  2344.       BlockX1 := pred(FirstCharPos) + CursorPosX;
  2345.       BlockY1 := pred(TopNode) + CursorPosY;
  2346.       if BlockActive(MemoDetails) then
  2347.          DisplayMemo(MemoDetails,HiStatus)
  2348.       else if WasActive then
  2349.          DisplayMemo(MemoDetails,HiStatus);
  2350.    end;
  2351. end; { MarkBlockStart }
  2352.  
  2353. procedure SetEndofBlock(var MemoDetails: MemoCfg);
  2354. {}
  2355. begin
  2356.    with MemoDetails do
  2357.    begin
  2358.       BlockX2 := pred(FirstCharPos) + CursorPosX;
  2359.       BlockY2 := pred(TopNode) + CursorPosY;
  2360.       DisplayMemo(MemoDetails,HiStatus);
  2361.    end;
  2362. end; { SetEndofBlock }
  2363.  
  2364. procedure SetStartofBlock(var MemoDetails: MemoCfg);
  2365. {}
  2366. begin
  2367.    with MemoDetails do
  2368.    begin
  2369.       BlockX1 := pred(FirstCharPos) + CursorPosX;
  2370.       BlockY1 := pred(TopNode) + CursorPosY;
  2371.       DisplayMemo(MemoDetails,HiStatus);
  2372.    end;
  2373. end; { SetStartofBlock }
  2374.  
  2375. procedure SetBlockStartEnd(var MemoDetails: MemoCfg);
  2376. {}
  2377. begin
  2378.    with MemoDetails do
  2379.    begin
  2380.       AtBlockStart := (BlockX1 = pred(FirstCharPos) + CursorPosX)
  2381.                        and
  2382.                        (BlockY1 = pred(TopNode) + CursorPosY);
  2383.       AtBlockEnd := (BlockX2 = pred(FirstCharPos) + CursorPosX)
  2384.                      and
  2385.                      (BlockY2 = pred(TopNode) + CursorPosY);
  2386.    end;
  2387. end; { SetBlockStartEnd }
  2388.  
  2389. procedure PrepareForMark(var MemoDetails: MemoCfg);
  2390. {}
  2391.      procedure NewBlock;
  2392.      {}
  2393.      begin
  2394.         with memodetails do
  2395.         begin
  2396.            AtBlockStart := true;
  2397.            AtBlockEnd := true;
  2398.            BlockX1 := pred(FirstCharPos) + CursorPosX;
  2399.            BlockY1 := pred(TopNode) + CursorPosY;
  2400.            BlockX2 := pred(FirstCharPos) + CursorPosX;
  2401.            BlockY2 := pred(TopNode) + CursorPosY;
  2402.         end;
  2403.      end; { NewBlock }
  2404.  
  2405. begin
  2406.    with MemoDetails do
  2407.    begin
  2408.       if not BlockActive(MemoDetails) then
  2409.         NewBlock
  2410.       else
  2411.       begin
  2412.          SetBlockStartEnd(MemoDetails);
  2413.          if not (AtBlockStart or AtBlockEnd) then
  2414.             NewBlock;
  2415.       end;
  2416.    end;
  2417. end; { PrepareForMark }
  2418.  
  2419. function CursorBeforeStart(var MemoDetails: MemoCfg): boolean;
  2420. {}
  2421. begin
  2422.    with MemoDetails do
  2423.    CursorBeforeStart := (BlockY1 > pred(TopNode) + CursorPosY)
  2424.                         or
  2425.                         ( (BlockY1 = pred(TopNode) + CursorPosY)
  2426.                           and
  2427.                           (BlockX1 > pred(FirstCharPos) + CursorPosX)
  2428.                         )
  2429. end; { CursorBeforeStart }
  2430.  
  2431. function CursorAfterEnd(var MemoDetails: MemoCfg): boolean;
  2432. {}
  2433. begin
  2434.    with MemoDetails do
  2435.    CursorAfterEnd    := (BlockY2 < pred(TopNode) + CursorPosY)
  2436.                         or
  2437.                         ( (BlockY2 = pred(TopNode) + CursorPosY)
  2438.                           and
  2439.                           (BlockX2 < pred(FirstCharPos) + CursorPosX)
  2440.                         )
  2441. end; { CursorAfterEnd }
  2442.  
  2443. procedure SetStarttoEnd(var MemoDetails: MemoCfg);
  2444. {}
  2445. begin
  2446.    with MemoDetails do
  2447.    begin
  2448.       BlockX2 := BlockX1;
  2449.       BlockY2 := BlockY1;
  2450.    end;
  2451. end; { SetStarttoEnd }
  2452.  
  2453. procedure SetEndtoStart(var MemoDetails: MemoCfg);
  2454. {}
  2455. begin
  2456.    with MemoDetails do
  2457.    begin
  2458.       BlockX1 := BlockX2;
  2459.       BlockY1 := BlockY2;
  2460.    end;
  2461. end; { SetEndtoStart}
  2462.  
  2463. procedure MarkNewBlock(var MemoDetails: MemoCfg;Backward:boolean);
  2464. {}
  2465. begin
  2466.    if Marking then
  2467.    begin
  2468.       if Backward then
  2469.       begin
  2470.          if AtBlockStart then
  2471.             SetStartOfBlock(MemoDetails)
  2472.          else if AtBlockEnd and CursorBeforeStart(MemoDetails) then
  2473.          begin
  2474.             SetStarttoEnd(MemoDetails);
  2475.             SetStartOfBlock(MemoDetails);
  2476.          end else
  2477.             SetEndOfBlock(MemoDetails);
  2478.       end else {forward}
  2479.       begin
  2480.          if AtBlockStart and AtBlockEnd then
  2481.             SetEndOfBlock(MemoDetails)
  2482.          else if AtBlockStart and CursorAfterEnd(MemoDetails) then
  2483.          begin
  2484.             SetEndtoStart(MemoDetails);
  2485.             SetEndOfBlock(MemoDetails);
  2486.          end else
  2487.          if AtBlockStart then
  2488.             SetStartOfBlock(MemoDetails)
  2489.          else
  2490.             SetEndOfBlock(MemoDetails);
  2491.       end;
  2492.    end;
  2493. end; { MarkNewBlock }
  2494.  
  2495. function UpOrDownKey(K:word): boolean;
  2496. {}
  2497. begin
  2498.    UpOrDownKey := (K = 336) or (K = 436) or (K = 328) or (K = 428);
  2499. end; { UpOrDownKey }
  2500. {$ELSE}
  2501. procedure MarkNewBlock(var MemoDetails: MemoCfg;Backward:boolean);
  2502. begin end;
  2503. {$ENDIF}
  2504.  
  2505.                          {************************}
  2506.                          {**  Mouse Management  **}
  2507.                          {************************}
  2508.  
  2509. procedure MemoScrollBar(var MemoDetails: MemoCfg);
  2510. {}
  2511. var L,M,R: boolean;
  2512.     X,Y,ElevatorY:byte;
  2513.     WaitTime: integer;
  2514.  
  2515.    procedure ScrollUpOne;
  2516.    {}
  2517.    begin
  2518.       with MemoDetails do
  2519.       repeat
  2520.          MouseStatusWin(L,M,R,X,Y);
  2521.          if (X = X2) and (Y = Y1) and L then
  2522.             CursorUp(MemoDetails);
  2523.          DelayIt(L,WindowHasFocus,WaitTime);
  2524.       until not L;
  2525.    end; { ScrollUpOne }
  2526.  
  2527.    procedure ScrollDownOne;
  2528.    {}
  2529.    begin
  2530.       with MemoDetails do
  2531.       repeat
  2532.          MouseStatusWin(L,M,R,X,Y);
  2533.          if (X = X2) and (Y = Y2) and L then
  2534.             CursorDown(MemoDetails);
  2535.          DelayIt(L,WindowHasFocus,WaitTime);
  2536.       until not L;
  2537.    end; { ScrollDownOne }
  2538.  
  2539.    procedure ScrollUpward;
  2540.    {}
  2541.    begin
  2542.       with MemoDetails do
  2543.       repeat
  2544.          MouseStatusWin(L,M,R,X,Y);
  2545.          if not ((TopNode = 1) and (CursorPosY = 1)) then
  2546.          begin
  2547.             if (X = X2) and (Y >= Y1) and (Y <= ElevatorY) and L then
  2548.                CursorPgUp(MemoDetails);
  2549.             DelayIt(L,WindowHasFocus,WaitTime);
  2550.          end;
  2551.       until not L;
  2552.    end; { ScrollUpward }
  2553.  
  2554.    procedure ScrollDownward;
  2555.    {}
  2556.    begin
  2557.       with MemoDetails do
  2558.       repeat
  2559.          MouseStatusWin(L,M,R,X,Y);
  2560.          if TopNode <> TotalNodes then
  2561.          begin
  2562.             if (X = X2) and (Y <= Y2) and (Y >= ElevatorY) and L then
  2563.                CursorPgDn(MemoDetails);
  2564.             DelayIt(L,WindowHasFocus,WaitTime);
  2565.          end;
  2566.       until not L;
  2567.    end; { ScrollDownward }
  2568.  
  2569.    procedure ScrollDragElevator;
  2570.    {}
  2571.    var
  2572.      OldY:byte;
  2573.      NewActive:longint;
  2574.    begin
  2575.       OldY := Y;
  2576.       with MemoDetails do
  2577.       repeat
  2578.          MouseStatusWin(L,M,R,X,Y);
  2579.          if (X = X2) and (Y < Y2) and (Y > Y1) and (Y <> OldY) and L then
  2580.          begin
  2581.             OldY := Y;
  2582.             if Y = succ(Y1) then
  2583.                CursorTop(MemoDetails)
  2584.             else if Y = pred(Y2) then
  2585.                CursorBottom(MemoDetails)
  2586.             else
  2587.             begin
  2588.                NewActive := TotalNodes * (Y - Y1) div (Y2-Y1);
  2589.                if NewActive <> pred(TopNode) + CursorPosY then
  2590.                begin
  2591.                   SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2592.                   CursorPosY := 1;
  2593.                   TopNode := NewActive;
  2594.                   LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2595.                   DisplayMemo(MemoDetails,HiStatus);
  2596.                end;
  2597.             end;
  2598.             if WindowHasFocus then
  2599.                WinDrawTop;
  2600.          end;
  2601.       until not L;
  2602.    end; { ScrollElevator }
  2603.  
  2604. begin
  2605.    with MemoDetails do
  2606.    begin
  2607.       WaitTime := KeyVars.InitScrollDelay;
  2608.       repeat
  2609.          MouseStatusWin(L,M,R,X,Y);
  2610.          if L and (X = X2) then
  2611.          begin
  2612.             if Y = Y1 then
  2613.                ScrollUpOne
  2614.             else if Y = Y2 then
  2615.                ScrollDownOne
  2616.             else    {mouse pressed along scroll bar body}
  2617.             begin
  2618.                ElevatorY := GetVScrollBarElevator(Y1,Y2,pred(TopNode)+CursorPosY,TotalNodes);
  2619.                if ((Y = succ(Y1)) and (Y=ElevatorY) and (pred(TopNode)+CursorPosY > 1))
  2620.                or (Y > Y1) and (Y < ElevatorY) then
  2621.                   ScrollUpward
  2622.                else if ((Y = pred(Y2)) and (Y=ElevatorY)
  2623.                         and
  2624.                         (pred(TopNode)+CursorPosY < TotalNodes)
  2625.                        )
  2626.                        or ((Y < Y2) and (Y > ElevatorY))  then
  2627.                   ScrollDownward
  2628.                else {user is dragging elevator}
  2629.                   ScrollDragElevator;
  2630.              end;
  2631.          end;
  2632.       until not L;
  2633.       MouseRelease;
  2634.    end;
  2635. end; { MemoScrollBar }
  2636.  
  2637. procedure AdjustCursor(var MemoDetails: MemoCfg; X,Y: byte);
  2638. {}
  2639. begin
  2640.    with Memodetails do
  2641.    begin
  2642.       SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  2643.       CursorPosY := Y;
  2644.       LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2645.       CursorPosX := X;
  2646.       CheckXandMove(MemoDetails);
  2647.    end;
  2648. end; { AdjustCursor }
  2649.  
  2650. procedure MouseDown(var MemoDetails: MemoCfg;StartX,StartY: byte);
  2651. {}
  2652. var L,M,R: boolean;
  2653.     AnchorY,
  2654.     LastY: longint;
  2655.     AnchorX,
  2656.     LastX,
  2657.     X,Y:byte;
  2658.  
  2659.    function Backward: boolean;
  2660.    {}
  2661.    begin
  2662.       with Memodetails do
  2663.       Backward := (Y + pred(TopNode) < LastY)
  2664.                   or
  2665.                   (
  2666.                      (Y + pred(TopNode) = LastY)
  2667.                      and
  2668.                      (X + pred(FirstCharPos) < LastX)
  2669.                   );
  2670.  
  2671.    end; { Backward }
  2672.  
  2673. begin
  2674.    with MemoDetails do
  2675.    begin
  2676.       X := StartX;
  2677.       Y := StartY;
  2678.       AdjustCursor(MemoDetails,X - pred(X1),Y-pred(Y1));
  2679.       LastX := StartX + pred(FirstCharPos);
  2680.       LastY := StartY + pred(TopNode);
  2681.       AnchorX := LastX;
  2682.       AnchorY := LastY;
  2683.    {$IFDEF CUTANDPASTE}
  2684.       Marking := true;
  2685.       PrepareForMark(MemoDetails);
  2686.       AnchorX := BlockX1;
  2687.       AnchorY := BlockY1;
  2688.    {$ENDIF}
  2689.       repeat
  2690.          MouseStatusWin(L,M,R,X,Y);
  2691.          if L and (X >= X1) and (X < X2) then
  2692.          begin
  2693.             if (Y >= Y1) and (Y <= Y2)  then
  2694.             begin
  2695.                AdjustCursor(MemoDetails,X - pred(X1),Y-pred(Y1));
  2696.                MarkNewBlock(MemoDetails,backward);
  2697.             end else
  2698.             if (Y <= pred(Y1)) and (pred(TopNode) + CursorPosY > 1)  then
  2699.             begin
  2700.                CursorUp(MemoDetails);
  2701.                MarkNewBlock(MemoDetails,true);
  2702.             end else
  2703.             if (Y >= succ(Y2)) and (pred(TopNode) + CursorPosY < TotalNodes) then
  2704.             begin
  2705.                CursorDown(MemoDetails);
  2706.                MarkNewBlock(MemoDetails,false);
  2707.             end;
  2708.          end;
  2709.          if WindowHasFocus and ((LastX <> X + pred(FirstCharPos))
  2710.                              or (LastY <> Y + pred(TopNode))
  2711.                            ) then
  2712.             WinDrawTop;
  2713.    {$IFDEF CUTANDPASTE}
  2714.          SetBlockStartEnd(MemoDetails);
  2715.    {$ENDIF}
  2716.          LastX := X + pred(FirstCharPos);
  2717.          LastY := Y + pred(TopNode);
  2718.       until not L;
  2719.       MouseRelease;
  2720.    end;
  2721. end; { MouseDown }
  2722.  
  2723. procedure HandleMouse(var MemoDetails: MemoCfg; X,Y: byte);
  2724. {}
  2725. begin
  2726.    with MemoDetails do
  2727.    begin
  2728.       if InWindow then {convert to local coords}
  2729.       begin
  2730.          X := WinLocalX(0,X);  {top window has handle of zero}
  2731.          Y := WinLocalY(0,Y);
  2732.       end;
  2733.       if (X = X2) and (TotalNodes > succ(Y2-Y1)) then {hit on scroll bar}
  2734.          MemoScrollBar(MemoDetails)
  2735.       else if (X >= X1) and (X < X2) and (Y >= Y1) and (Y <= Y2) then
  2736.          MouseDown(MemoDetails,X,Y)
  2737.       else
  2738.          MouseRelease;
  2739.    end;
  2740. end; { HandleMouse }
  2741.  
  2742. procedure HandleZoom(var MemoDetails: MemoCfg; X,Y: byte);
  2743. {}
  2744. var WP: WStructurePtr;
  2745. begin
  2746.    {First set the memodetails to reflect the revised window dimensions}
  2747.    WP := WinPtr(0); {top window}
  2748.    with MemoDetails do
  2749.    begin
  2750.       WX1 := WP^.X;
  2751.       WY1 := WP^.Y;
  2752.       WX2 := WX1 + pred(WP^.Width);
  2753.       WY2 := WY1 + pred(WP^.Depth);
  2754.       SetInnerDimensions(MemoDetails);
  2755.       SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr); {save edits}
  2756.       if WordWrap then
  2757.       begin
  2758.          FirstCharPos := 1;
  2759.          CursorPosX := 1;
  2760.          TopNode := 1;
  2761.          CursorPosY := 1;
  2762.          MaxWidth := X2-X1;
  2763. {$IFDEF WORDWRAP}
  2764.          WrapFull(Memodetails)
  2765. {$ELSE}
  2766.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2767. {$ENDIF}
  2768.       end else
  2769.       begin
  2770.  
  2771.       end;
  2772.       DisplayMemo(MemoDetails,HiStatus);
  2773.       if CursorPosY > (Y2-Y1) then
  2774.       begin
  2775.          CursorPosY := 1;
  2776.          LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  2777.       end;
  2778.       CheckXandMove(Memodetails);
  2779.    end;
  2780.    WinDrawAll;
  2781. end; { HandleZoom }
  2782.  
  2783. {$IFDEF CUTANDPASTE}
  2784. procedure SelectWord(var MemoDetails: MemoCfg; X,Y: byte);
  2785. {}
  2786. var LastX,EndX: byte;
  2787. begin
  2788.    with MemoDetails do
  2789.    begin
  2790.       if InWindow then {convert to local coords}
  2791.       begin
  2792.          X := WinLocalX(0,X);
  2793.          Y := WinLocalY(0,Y);
  2794.       end;
  2795.       if (X >= X1) and (X < X2) and (Y >= Y1) and (Y <= Y2) then
  2796.       begin
  2797.          X := X - pred(X1);
  2798.          Y := Y - pred(Y1);
  2799.          LastX := X;
  2800.          AdjustCursor(MemoDetails,X,Y);
  2801.          TurnBlockOff(MemoDetails);
  2802.          if (LastX = X) and (LineStr[pred(FirstCharPos)+ X] <> ' ') then {wasn't past the end of the line & not a space}
  2803.          begin
  2804.             while (LastX > 1) and (LineStr[LastX] <> ' ') do
  2805.                dec(LastX);
  2806.             if LineStr[LastX] = ' ' then
  2807.                inc(LastX);
  2808.             EndX := LastX;
  2809.             while (EndX < length(LineStr))
  2810.               and (LineStr[EndX] <> MemoVars.EndofParaCode)
  2811.               and (LineStr[EndX] <> ' ')
  2812.               and not (LineStr[EndX] in PuncChars) do
  2813.                  inc(EndX);
  2814.             if (LineStr[EndX] = ' ') then
  2815.                inc(EndX);
  2816.             {time to highlight the word}
  2817.             BlockX1 := LastX;
  2818.             BlockX2 := EndX;
  2819.             BlockY1 := pred(TopNode) + CursorPosY;
  2820.             BlockY2 := BlockY1;
  2821.             if EndX = length(LineStr) then
  2822.                inc(BlockX2);
  2823.             DisplayMemo(MemoDetails,HiStatus);
  2824.             if WindowHasFocus then
  2825.                WinDrawTop;
  2826.             MouseRelease;
  2827.          end;
  2828.       end;
  2829.    end;
  2830. end; { SelectWord }
  2831. {$ENDIF}
  2832.  
  2833.                           {**********************}
  2834.                           {**  MemoProcessKey  **}
  2835.                           {**********************}
  2836.  
  2837. procedure MemoProcessKey(var MemoDetails: MemoCfg;var K:word;X,Y:byte);
  2838. {}
  2839. var gResult: integer;
  2840. begin {MemoProcessKey}
  2841.    with MemoVars do
  2842.    with MemoDetails do
  2843.    begin
  2844.       CharHook(@Memodetails,K,X,Y); {call user hook}
  2845.       if InWindow then
  2846.          if IsWinKey(K,X,Y) then
  2847.             WinProcessKey(K,X,Y);
  2848. {$IFDEF CUTANDPASTE}
  2849.       Marking := KeyShiftPressed and (K > 265);
  2850.       if Marking then
  2851.          PrepareForMark(MemoDetails);
  2852. {$ENDIF}
  2853.       if K = WordRightKey then
  2854.       begin
  2855.          CursorRightWord(MemoDetails);
  2856.          MarkNewBlock(MemoDetails,false);
  2857.       end
  2858.       else if K =  WordLeftKey then
  2859.       begin
  2860.          CursorLeftWord(MemoDetails);
  2861.          MarkNewBlock(MemoDetails,true);
  2862.       end
  2863.       else if K =  TopOfWindowKey then
  2864.       begin
  2865.  
  2866.          MarkNewBlock(MemoDetails,true);
  2867.       end
  2868.       else if K =  BotOfWindowKey then
  2869.       begin
  2870.  
  2871.          MarkNewBlock(MemoDetails,false);
  2872.       end
  2873.       else if K =  TopofMemoKey then
  2874.       begin
  2875.          CursorTop(MemoDetails);
  2876.          MarkNewBlock(MemoDetails,true);
  2877.       end
  2878.       else if K =  BotofMemoKey then
  2879.       begin
  2880.          CursorBottom(MemoDetails);
  2881.          MarkNewBlock(MemoDetails,false);
  2882.       end
  2883. {$IFDEF CUTANDPASTE}
  2884.       else if K =  DeltoScrapKey then
  2885.          DeltoClipboard(Memodetails)
  2886.       else if K =  CopyToScrapkey then
  2887.          gResult := CopytoClipboard(Memodetails)
  2888.       else if K =  InsfromScrapKey then
  2889.       begin
  2890.          if MemoDetails.WordWrap then
  2891. {$IFDEF WORDWRAP}
  2892.            WWInsFromClipboard(Memodetails)
  2893. {$ENDIF}
  2894.          else
  2895.            InsFromClipboard(Memodetails);
  2896.       end
  2897.       else if K =  MarkBlockStartKey then
  2898.          MarkBlockStart(Memodetails)
  2899.       else if K =  MarkBlockEndKey then
  2900.          MarkBlockEnd(Memodetails)
  2901.       else if K =  HideBlockKey then
  2902.          TurnBlockOff(Memodetails)
  2903.       else if K =  DelBlockKey then
  2904.          EraseBlock(Memodetails)
  2905. {$ENDIF}
  2906.       else
  2907.       case K of
  2908.          500: begin
  2909.             HandleMouse(MemoDetails,X,Y);
  2910.          end;
  2911.          540: begin  {double click -- highlight the word}
  2912. {$IFDEF CUTANDPASTE}
  2913.             SelectWord(MemoDetails,X,Y);
  2914. {$ENDIF}
  2915.          end;
  2916.          602: begin  {window has been zoomed - refresh}
  2917.             HandleZoom(MemoDetails,X,Y);
  2918.          end;
  2919.          328,428: begin
  2920.             CursorUp(MemoDetails);
  2921.             MarkNewBlock(MemoDetails,true);
  2922.          end;
  2923.          336,436: begin
  2924.             CursorDown(MemoDetails);
  2925.             MarkNewBlock(MemoDetails,false);
  2926.          end;
  2927.          337,437: begin
  2928.             CursorPgDn(MemoDetails);
  2929.             MarkNewBlock(MemoDetails,false);
  2930.          end;
  2931.          329,429: begin
  2932.             CursorPgUp(MemoDetails);
  2933.             MarkNewBlock(MemoDetails,true);
  2934.          end;
  2935.          335,435: begin
  2936.             CursorEnd(MemoDetails);
  2937.             MarkNewBlock(MemoDetails,false);
  2938.          end;
  2939.          327,427: begin
  2940.             CursorHome(MemoDetails);
  2941.             MarkNewBlock(MemoDetails,true);
  2942.          end;
  2943.          333,433: begin
  2944.             CursorRight(MemoDetails);
  2945.             MarkNewBlock(MemoDetails,false);
  2946.          end;
  2947.          331,431: begin
  2948.             CursorLeft(MemoDetails);
  2949.             MarkNewBlock(MemoDetails,true);
  2950.          end;
  2951.          else if AllowEdits then
  2952.          case K of
  2953.             13,10:  ProcessEnter(MemoDetails);
  2954.             8:   BackSpace(MemoDetails);
  2955.             338: begin
  2956.                InsertOn := not InsertOn;
  2957.                InsMode(InsertOn);
  2958.             end;
  2959.             339: begin
  2960. {$IFDEF WORDWRAP}
  2961.                if Wordwrap then
  2962.                   WrapDeleteChar(Memodetails)
  2963.                else
  2964. {$ENDIF}
  2965.                DeleteChar(MemoDetails);
  2966.             end;
  2967. 97: begin
  2968.    ProcessChar(MemoDetails,chr(K));
  2969. end;
  2970.             32..255: ProcessChar(MemoDetails,chr(K));
  2971.          end;
  2972.       end;
  2973. {$IFDEF CUTANDPASTE}
  2974.       if not UporDownKey(K) then
  2975.          TargetPosX := 0;
  2976. {$ENDIF}
  2977.       HindHook(@Memodetails);
  2978.    end;
  2979. end; { MemoProcessKey }
  2980.  
  2981.                      {********************************}
  2982.                      {**  Window Editing Functions  **}
  2983.                      {********************************}
  2984.  
  2985. function Finished(K:word): boolean;
  2986. {}
  2987. begin
  2988.    with MemoVars do
  2989.       Finished :=  (K = 600)
  2990.                    or (K = EndEditKey)
  2991.                    or (K = EscEditKey);
  2992. end; { Finished }
  2993.  
  2994.  
  2995. function DisplayMemoEngine(var MemoDetails: MemoCfg;Tit:StrScreen): byte;
  2996. {INTERNAL}
  2997. var
  2998.   Handle: integer;
  2999.  
  3000.    procedure SetWindow;
  3001.    {}
  3002.    begin
  3003.       with MemoDetails do
  3004.       begin
  3005.          Handle := WinCreate(WX1,WY1,WX2,WY2,WStyle);
  3006.          WinSetType(Handle,WiType);
  3007.          WinSetTitle(Handle,Tit);
  3008.          WinSetShowNum(Handle,false);
  3009.          WinSetColor(Handle,WinBorder,Col[MemoBorder1]);
  3010.          WinSetColor(Handle,WinBorder3DOut,Col[MemoBorder1]);
  3011.          WinSetColor(Handle,WinBorder3dIn,Col[MemoBorder2]);
  3012.          WinSetColor(Handle,WinBorderOff,Col[MemoBorderOff]);
  3013.          WinSetColor(Handle,WinIcons,Col[MemoIcons]);
  3014.          WinSetColor(Handle,WinBody,Col[MemoHi]);
  3015.          WinSetColor(Handle,WinTitle,Col[MemoTitle]);
  3016.          WinPaint(Handle);
  3017.       end;
  3018.    end; {SetWindow}
  3019.  
  3020. begin
  3021.    with MemoDetails do
  3022.    begin
  3023. {$IFNDEF WORDWRAP}
  3024.       if Wordwrap then
  3025.       begin
  3026.          MemoWarning(3);
  3027.          Wordwrap := false;
  3028.       end;
  3029. {$ENDIF}
  3030.       if WX1 = 0 then  {user hasn't set the window}
  3031.       begin
  3032.          WX1 := MemoVars.WX1;
  3033.          WY1 := MemoVars.WY1;
  3034.          WX2 := MemoVars.WX2;
  3035.          WY2 := MemoVars.WY2;
  3036.       end;
  3037.       SetInnerDimensions(MemoDetails);
  3038.       SetWindow;
  3039.       InWindow := true;
  3040.       {wrap that wrascal}
  3041.       if Wordwrap then
  3042.          MaxWidth := X2-X1
  3043.       else
  3044.          MaxWidth := MemoVars.DefaultLineLength;
  3045. {$IFDEF WORDWRAP}
  3046.       with Memodetails do
  3047.          if WordWrap then
  3048.             WrapFull(MemoDetails)
  3049.          else
  3050.             LineStr := GetLine(@Memodetails,pred(TopNode)+CursorPosY);
  3051. {$ELSE}
  3052.       with MemoDetails do
  3053.           LineStr := GetLine(@MemoDetails,pred(TopNode)+CursorPosY);
  3054. {$ENDIF}
  3055.       WinDisplay(Handle);
  3056.       DisplayMemo(MemoDetails,HiStatus);
  3057.       MoveCursor(MemoDetails);
  3058.       DisplayMemoEngine := handle;
  3059.       MemoDetails.HindHook(@MemoDetails); {call it once after window is created}
  3060.       WinDrawAll;
  3061.    end;
  3062. end; { DisplayMemoEngine }
  3063.  
  3064. procedure RunMemo(var MemoDetails: MemoCfg;Tit:StrScreen);
  3065. {}
  3066. var
  3067.    Handle: integer;
  3068.    K: word;
  3069.    X,Y: byte;
  3070.  
  3071. begin
  3072.    Handle := DisplayMemoEngine(MemoDetails,Tit);
  3073.    with MemoDetails do
  3074.    begin
  3075.       InsMode(InsertOn);
  3076.       {ready for input}
  3077.       repeat
  3078.          GetInput;
  3079.          with KeyVars do
  3080.          begin
  3081.             K := LastKey;
  3082.             X := LastX;
  3083.             Y := LastY;
  3084.          end;
  3085.          MemoProcessKey(MemoDetails,K,X,Y);
  3086.          WinDrawTop;
  3087.       until Finished(K);
  3088.       {time to shut down}
  3089.       with MemoDetails do
  3090.            SetLine(@MemoDetails,pred(TopNode)+CursorPosY,LineStr);
  3091.       WinDispose(Handle);
  3092. {$IFDEF CUTANDPASTE}
  3093.       ClearClipboardBuffer;  {empty the buffer before quitting}
  3094. {$ENDIF}
  3095.       MouseRelease;
  3096.    end; {with}
  3097. end; {RunMemo}
  3098.  
  3099.                         {**************************}
  3100.                         {**  Desktop Management  **}
  3101.                         {**************************}
  3102.  
  3103. {$IFOPT F-}
  3104.    {$DEFINE FOFF}
  3105.    {$F+}
  3106. {$ENDIF}
  3107. function MemoCloseHandler(Handle: integer): boolean;
  3108. {}
  3109. var
  3110.    WinP: WStructurePtr;
  3111. begin
  3112.    WinP := WinPtr(Handle);
  3113.    if MemoCfg(Winp^.UserData^).DeskMemoCloseCallBack(Winp^.UserData,Handle) then
  3114.    begin
  3115.       WinDispose(Handle);
  3116.       MemoCloseHandler := true;
  3117.    end
  3118.    else
  3119.       MemoCloseHandler := false;
  3120. end; {MemoCloseHandler}
  3121.  
  3122. procedure MemoProcessKeyOnDesktop;
  3123. {}
  3124. var
  3125.    Handle: integer;
  3126.    WinP: WStructurePtr;
  3127.    MDP : ^MemoCfg;
  3128. begin
  3129.    Handle := WinWithFocus;
  3130.    WinP := WinPtr(Handle);
  3131.    MDP := Winp^.UserData;
  3132.    with KeyVars do
  3133.    begin
  3134.       MemoProcessKey(MDP^,LastKey,LastX,LastY);
  3135.       if Finished(LastKey) then
  3136.          if MemoCloseHandler(Handle) then
  3137.             {close aborted};
  3138.    end;
  3139. end; { MemoProcessKeyOnDesktop }
  3140.  
  3141. procedure MemoFocusHandler(Handle: integer);
  3142. {}
  3143. var
  3144.    WinP: WStructurePtr;
  3145. begin
  3146.    WinP := WinPtr(Handle);
  3147.    with MemoCfg(WinP^.UserData^) do
  3148.    begin
  3149.       case DataType of
  3150.          SourceSLL: SLLSetActiveList(SingleLL(DataSource^));
  3151.          SourceDLL: DLLSetActiveList(DoubleLL(DataSource^));
  3152.       end;
  3153.    end;
  3154. end; {MemoFocusHandler}
  3155. {$IFDEF FOFF}
  3156.    {$F-}
  3157.    {$UNDEF FOFF}
  3158. {$ENDIF}
  3159.  
  3160. function LaunchMemo(var MemoDetails: MemoCfg;Tit:StrScreen; CloseProc:MemoCloseProc): byte;
  3161. {}
  3162. var
  3163.    WinP: WStructurePtr;
  3164.    Handle: byte;
  3165. begin
  3166.    WinFadeTopWin;
  3167.    MemoDetails.DeskMemoCloseCallBack := CloseProc;
  3168.    if WinVars.DesktopFocusStyle <> 0 then
  3169.       MemoDetails.WStyle := WinVars.DesktopFocusStyle;
  3170.    Handle := DisplayMemoEngine(Memodetails,Tit);
  3171.    if Handle = 0 then
  3172.       MemoSetError(1001)
  3173.    else
  3174.    begin
  3175.       WinP := WinPtr(Handle);
  3176.       WinP^.ProcessKeyProc := MemoProcessKeyOnDeskTop;
  3177.       WinP^.CloseWinProc := MemoCloseHandler;
  3178.       WinP^.ChangeFocusProc := MemoFocusHandler;
  3179.       WinP^.UserData := @MemoDetails;
  3180.    end;
  3181.    WinDrawTop;
  3182.    CursorOn;
  3183.    LaunchMemo := Handle;
  3184. end; {LaunchMemo}
  3185.  
  3186.               {*********************************************}
  3187.               {**  U N I T   I N I T I A L I Z A T I O N  **}
  3188.               {*********************************************}
  3189.  
  3190. procedure MemoDefaultSettings;
  3191. {}
  3192. begin
  3193.    with MemoVars do
  3194.    begin
  3195.       WordRightKey := 372;    {Ctrl-Right}
  3196.       WordLeftKey := 371;     {Ctrl-Left}
  3197.       TopOfWindowKey := 375;  {Ctrl-Home}
  3198.       BotOfWindowKey := 373;  {Ctrl-End}
  3199.       TopofMemoKey := 388;    {Ctrl-PgUp}
  3200.       BotofMemoKey := 374;    {Ctrl-PgDn}
  3201.       DeltoScrapKey := 263;   {Shift-Del}
  3202.       DelBlockKey := 339;     {Del}
  3203.       CopyToScrapkey := 260;  {Ctrl-Ins}
  3204.       InsfromScrapKey := 261; {Shift-Ins}
  3205.       MarkBlockStartKey := 321; {F7}
  3206.       MarkBlockEndKey := 322; {F8}
  3207.       HideBlockKey := 2;      {Ctrl-B}
  3208.       EndofParaCode := chr(20); {}
  3209.       EndEditKey := 324;      {F10}
  3210.       EscEditKey := 27;       {Esc}
  3211.       DefaultLineLength := 127;
  3212.       {window settings}
  3213.       WinStyle := 4;
  3214.       WType := WStretch;
  3215.       WX1 := 10;
  3216.       WY1 := 5;
  3217.       WX2 := 70;
  3218.       WY2 := 20;
  3219.       {Messages}
  3220.       ClipboardMsgTitle := ' Clipboard Error ';
  3221.       WarningTitle := ' Warning ';
  3222.       ClipboardNoMemoryMsg := 'Insufficient memory to copy text to clipboard.';
  3223.       ClipboardLowMemoryMsg := 'Low memory -- unable to copy entire text to to clipboard.';
  3224.       ClipboardLineFullMsg := 'Line too long -- unable to insert text from clipboard.';
  3225.       MaxLinesMsg := 'Memo is full -- unable insert a line.';
  3226.       MemoNearlyFullMsg := 'The memo is nearly full. Text on the last line may be erased to make space.';
  3227.       WordwrapoffMsg := 'Internal error -- program not compiled to support word wrapping!';
  3228.       LineFullMsg := 'The line is full. Press Ins to change to overtype|mode or delete some characters.';
  3229.    end;
  3230. end; { MemoDefaultSettings }
  3231.  
  3232. procedure GoldMEMOInit;
  3233. {}
  3234. begin
  3235.    Memovars.LastEcode := 0;
  3236.    MemodefaultSettings;
  3237.    MemoVars.Clipboard := nil;
  3238. end; {GoldMEMOInit}
  3239.  
  3240. begin
  3241.    GoldMEMOInit;
  3242. end.
  3243.